ftown 0.25.2 → 0.25.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/command-rpc.d.ts +3 -0
- package/dist/command-rpc.js +41 -0
- package/dist/command-rpc.js.map +1 -1
- package/dist/ftown-cli.js +5 -2
- package/dist/ftown-cli.js.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/quota/agy.d.ts +16 -0
- package/dist/quota/agy.js +287 -0
- package/dist/quota/agy.js.map +1 -0
- package/dist/quota/annotate.d.ts +5 -0
- package/dist/quota/annotate.js +56 -0
- package/dist/quota/annotate.js.map +1 -0
- package/dist/quota/claude.d.ts +27 -0
- package/dist/quota/claude.js +265 -0
- package/dist/quota/claude.js.map +1 -0
- package/dist/quota/codex.d.ts +25 -0
- package/dist/quota/codex.js +378 -0
- package/dist/quota/codex.js.map +1 -0
- package/dist/quota/format.d.ts +6 -0
- package/dist/quota/format.js +113 -0
- package/dist/quota/format.js.map +1 -0
- package/dist/quota/grok.d.ts +97 -0
- package/dist/quota/grok.js +563 -0
- package/dist/quota/grok.js.map +1 -0
- package/dist/quota/models-agy.d.ts +10 -0
- package/dist/quota/models-agy.js +144 -0
- package/dist/quota/models-agy.js.map +1 -0
- package/dist/quota/models-claude.d.ts +10 -0
- package/dist/quota/models-claude.js +227 -0
- package/dist/quota/models-claude.js.map +1 -0
- package/dist/quota/models-codex.d.ts +18 -0
- package/dist/quota/models-codex.js +305 -0
- package/dist/quota/models-codex.js.map +1 -0
- package/dist/quota/models-grok.d.ts +19 -0
- package/dist/quota/models-grok.js +272 -0
- package/dist/quota/models-grok.js.map +1 -0
- package/dist/quota/models-muse.d.ts +13 -0
- package/dist/quota/models-muse.js +200 -0
- package/dist/quota/models-muse.js.map +1 -0
- package/dist/quota/models-opencode.d.ts +51 -0
- package/dist/quota/models-opencode.js +400 -0
- package/dist/quota/models-opencode.js.map +1 -0
- package/dist/quota/muse.d.ts +38 -0
- package/dist/quota/muse.js +225 -0
- package/dist/quota/muse.js.map +1 -0
- package/dist/quota/opencode.d.ts +7 -0
- package/dist/quota/opencode.js +47 -0
- package/dist/quota/opencode.js.map +1 -0
- package/dist/quota/routing-config.d.ts +18 -0
- package/dist/quota/routing-config.js +438 -0
- package/dist/quota/routing-config.js.map +1 -0
- package/dist/quota/routing-service.d.ts +24 -0
- package/dist/quota/routing-service.js +118 -0
- package/dist/quota/routing-service.js.map +1 -0
- package/dist/quota/routing.d.ts +10 -0
- package/dist/quota/routing.js +180 -0
- package/dist/quota/routing.js.map +1 -0
- package/dist/quota/types.d.ts +304 -0
- package/dist/quota/types.js +45 -0
- package/dist/quota/types.js.map +1 -0
- package/dist/quota-cli.d.ts +80 -0
- package/dist/quota-cli.js +462 -0
- package/dist/quota-cli.js.map +1 -0
- package/dist/security/bridge/permissions.js +4 -2
- package/dist/security/bridge/permissions.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/package.json +3 -2
- package/skills/ftown/SKILL.md +2 -1
- package/skills/ftown/references/orchestrator.md +5 -0
- package/skills/ftown/references/quota.md +177 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Quota-aware routing
|
|
2
|
+
|
|
3
|
+
Read `../SKILL.md` for identity and reporting. This reference covers choosing the
|
|
4
|
+
CLI, model and effort for delegated work. The owner sets up tiers; you choose.
|
|
5
|
+
`ftown quota` reports data and never chooses for you.
|
|
6
|
+
|
|
7
|
+
## When to use
|
|
8
|
+
|
|
9
|
+
- Before `ftown sessions create` for a child whose harness you are free to pick.
|
|
10
|
+
- When a worker stopped on a usage limit, before re-routing its task.
|
|
11
|
+
- Not needed when the user named the harness or model. Keep their choice.
|
|
12
|
+
|
|
13
|
+
## What to run
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ftown quota --json # full report
|
|
17
|
+
ftown quota claude codex --json # only the named harnesses
|
|
18
|
+
ftown quota --json --no-models # skip model lists (picks become unchecked)
|
|
19
|
+
ftown quota --json --timeout 30 # per-harness limit, 1-600 s, default 15
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Harnesses: `claude`, `codex`, `grok`, `muse`, `agy`, `opencode`. If `ftown` is
|
|
23
|
+
not on PATH, use `~/.ftown/ftown quota`. `--models` only affects table mode.
|
|
24
|
+
|
|
25
|
+
A run takes several seconds. It launches hidden local CLIs to read their usage
|
|
26
|
+
and model lists. It makes no model turns. The numbers describe the owner's
|
|
27
|
+
subscription plans (5-hour and weekly windows), not API spend.
|
|
28
|
+
|
|
29
|
+
## Decision procedure
|
|
30
|
+
|
|
31
|
+
The owner configures tiers in the dashboard ("Model routing..." on a bridge).
|
|
32
|
+
Each tier has a `name`, a `description` of the work it is for, an ordered list of
|
|
33
|
+
`picks` (CLI + model + effort), and free-text `guidance`. The report also has a
|
|
34
|
+
global free-text `steering`.
|
|
35
|
+
|
|
36
|
+
1. Read `routingConfig.status`. If it is not `ok`, see "When things are missing".
|
|
37
|
+
2. Match the task to a tier by the tier `description`s. Pick the closest one.
|
|
38
|
+
3. Walk that tier's `picks` in order. Skip any pick whose `problem` is not null:
|
|
39
|
+
the model is gone or the effort is unsupported.
|
|
40
|
+
4. Weigh each remaining pick: `availability`, `leftPercent` (null when `unknown`),
|
|
41
|
+
`resetsAt` (null when `unknown`), and `scopedLimits`. A scoped limit (for example
|
|
42
|
+
one model family) can be tighter than the plan-wide figure. Scopes usually name a
|
|
43
|
+
model family that appears in the model id or name, so matching a scope to a pick
|
|
44
|
+
is your judgment; when several match use the one with most used.
|
|
45
|
+
5. `checked: false` means the harness's model list could not be read, so the pick
|
|
46
|
+
was not verified. It is usable with care: expect a possible launch failure.
|
|
47
|
+
6. Apply the tier's `guidance` and the global `steering`. They are the owner's
|
|
48
|
+
instructions and outrank the pick order when they conflict. Example: if
|
|
49
|
+
steering says "don't fully exhaust Claude", skip a Claude pick that is `low`
|
|
50
|
+
even when it is first.
|
|
51
|
+
7. Guidance is free text and may name a class, such as "otherwise any free
|
|
52
|
+
opencode model". Resolve it against `models`: filter that provider's
|
|
53
|
+
`models[].models[]` by `pricing` and choose one that fits the task. If that
|
|
54
|
+
provider's list is empty you cannot resolve the class, so fall back to `routing[]`
|
|
55
|
+
and say so. `pricing` is `free` (zero-priced), `included` (covered by a plan the
|
|
56
|
+
owner holds) or `paid` (billed per use). It is omitted when unknown.
|
|
57
|
+
8. Launch the choice (next section). Report to the user which tier and pick you
|
|
58
|
+
used, and why if you departed from the pick order.
|
|
59
|
+
|
|
60
|
+
## Availability values
|
|
61
|
+
|
|
62
|
+
Each pick carries its provider's `availability`. The same values appear in `routing[]`.
|
|
63
|
+
|
|
64
|
+
- `available`: enough left for normal work. Use it.
|
|
65
|
+
- `low`: `leftPercent` below 15 in the binding (tightest) window, or `runway`
|
|
66
|
+
below 0.5 when `runway` is not null. Use only for small tasks, when guidance
|
|
67
|
+
allows it, or when nothing `available` fits.
|
|
68
|
+
- `exhausted`: `leftPercent` 1 or less. Never use it before `resetsAt`.
|
|
69
|
+
- `unknown`: no usable numbers. It is not proof of empty or full quota. It ranks
|
|
70
|
+
below `low` and above `exhausted`; use it as a fallback after `available` and
|
|
71
|
+
`low`, and say so.
|
|
72
|
+
|
|
73
|
+
If a window resets within 10 minutes it is reported as `available` with `leftPercent`
|
|
74
|
+
100 and `runway` null, even if `usedPercent` was high. `routing[]` is ordered best
|
|
75
|
+
first as available, then low, then unknown, then exhausted.
|
|
76
|
+
|
|
77
|
+
`leftPercent` is percent left in the binding (tightest) window. `windows[].usedPercent`
|
|
78
|
+
in `providers` is percent used. Do not mix them up.
|
|
79
|
+
|
|
80
|
+
## Turning a pick into a launch
|
|
81
|
+
|
|
82
|
+
Find the provider's entry in `models`. It gives `modelFlag` (for example
|
|
83
|
+
`--model <id>`) and `effortFlag` (for example `--effort <level>`, or null when
|
|
84
|
+
the harness has no effort flag). Use the pick's `model` as the id, verbatim, and
|
|
85
|
+
its `effort` as the level. `effort: null` means omit the effort flag.
|
|
86
|
+
|
|
87
|
+
opencode takes effort as a `#variant` suffix on the model, for example
|
|
88
|
+
`provider/model#high`. Check its `effortFlag` and the model's `efforts` in the report.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
ftown sessions create --shell <provider> --model <id> --parent \
|
|
92
|
+
--workdir "$PWD" --name review-auth --prompt "..."
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Where `ftown sessions create` has no flag for the effort, apply `effortFlag` as
|
|
96
|
+
the harness documents it. Omit `--model` to take the harness default.
|
|
97
|
+
|
|
98
|
+
## When things are missing
|
|
99
|
+
|
|
100
|
+
- `routingConfig.status` is `missing`: the owner has set no tiers. `tiers` is
|
|
101
|
+
empty. Walk `routing[]` in order (already best first: available, low, unknown,
|
|
102
|
+
exhausted): take the first `available`, else `low` only for small tasks, else
|
|
103
|
+
`unknown` with disclosure, and never use `exhausted` before its `resetsAt`.
|
|
104
|
+
Pick a model from `models` and tell the user no tiers are configured.
|
|
105
|
+
- `routingConfig.status` is `invalid`: `routingConfig.errors` lists the problems.
|
|
106
|
+
Treat it like `missing`, and tell the user the file at `routingConfig.path`
|
|
107
|
+
needs fixing. Still honor `steering` if it is non-empty.
|
|
108
|
+
- An empty tier (no `picks`): use its `guidance` if it has any; otherwise fall
|
|
109
|
+
back to `routing[]`.
|
|
110
|
+
- Every pick unusable (all have a `problem`, or are `exhausted`): follow the
|
|
111
|
+
guidance if it names an alternative. Otherwise try the next closest tier, then
|
|
112
|
+
`routing[]`. If nothing is usable, stop and ask the user rather than launching
|
|
113
|
+
on an exhausted plan.
|
|
114
|
+
- A provider with `status` other than `ok` (`no_data`, `auth`, `unavailable`,
|
|
115
|
+
`error`): read its `message`. Its routing is `unknown`. For `auth`, tell the
|
|
116
|
+
user what to fix. A `models` entry with status other than `ok` has an empty
|
|
117
|
+
`models` list, so its picks are `checked: false`.
|
|
118
|
+
- opencode may expose no plan usage at all, so when it reports no windows its
|
|
119
|
+
availability will be `unknown`. That is expected when it happens. Judge it by
|
|
120
|
+
`pricing` (`free` models are safe to use) and by the owner's guidance, not by
|
|
121
|
+
quota.
|
|
122
|
+
|
|
123
|
+
## JSON field reference
|
|
124
|
+
|
|
125
|
+
| Field | Meaning |
|
|
126
|
+
|---|---|
|
|
127
|
+
| `generatedAt` | ISO time of the report |
|
|
128
|
+
| `providers[]` | raw readings: `provider`, `status`, `plan`, `windows[]`, `source`, `observedAt`, `message`, optional `scopedLimits[]` |
|
|
129
|
+
| `providers[].windows[]` | `kind` (`five_hour`/`weekly`), `usedPercent` (used, may be null), `resetsAt`, `windowMinutes`, `note` |
|
|
130
|
+
| `scopedLimits[]` | partial limit: `scope` (e.g. a model family), `kind`, `usedPercent`, `resetsAt` |
|
|
131
|
+
| `routing[]` | per provider, best first: `provider`, `availability`, `leftPercent`, `bindingWindow`, `resetsAt`, `resetsInMinutes`, `runway` (1 = on pace, >1 spare, <1 will run out early, null when length or reset unknown), `reason` |
|
|
132
|
+
| `models[]` | per provider: `provider`, `status` (`ok`/`unavailable`/`error`; empty `models` unless `ok`), `models[]`, `source` (`live`/`cached`), `observedAt`, `message`, `modelFlag`, `effortFlag` |
|
|
133
|
+
| `models[].models[]` | `id`, `name`, `isDefault`, `description`, `contextTokens`, `efforts[]`, `defaultEffort`, optional `pricing` |
|
|
134
|
+
| `routingConfig` | `status` (`ok`/`missing`/`invalid`), `path`, `errors[]` |
|
|
135
|
+
| `tiers[]` | `name`, `description`, `picks[]`, `guidance`. Empty unless status is `ok` |
|
|
136
|
+
| `tiers[].picks[]` | `provider`, `model`, `effort`, `modelName`, `availability`, `leftPercent`, `resetsAt`, `scopedLimits[]`, `problem`, `checked` |
|
|
137
|
+
| `steering` | global owner instructions, verbatim, `""` when none |
|
|
138
|
+
|
|
139
|
+
Trimmed example (invented values):
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"routingConfig": { "status": "ok", "path": "/home/u/.ftown/model-routing.json", "errors": [] },
|
|
144
|
+
"steering": "Don't fully exhaust Claude.",
|
|
145
|
+
"tiers": [
|
|
146
|
+
{
|
|
147
|
+
"name": "complex",
|
|
148
|
+
"description": "Hard development and debugging",
|
|
149
|
+
"guidance": "Otherwise any free opencode model.",
|
|
150
|
+
"picks": [
|
|
151
|
+
{ "provider": "claude", "model": "model-a", "effort": "high", "modelName": "Model A",
|
|
152
|
+
"availability": "low", "leftPercent": 9, "resetsAt": "2026-01-05T00:00:00Z",
|
|
153
|
+
"scopedLimits": [], "problem": null, "checked": true },
|
|
154
|
+
{ "provider": "codex", "model": "model-b", "effort": "medium", "modelName": null,
|
|
155
|
+
"availability": "available", "leftPercent": 70, "resetsAt": "2026-01-06T00:00:00Z",
|
|
156
|
+
"scopedLimits": [], "problem": null, "checked": true }
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
"models": [
|
|
161
|
+
{ "provider": "codex", "status": "ok", "modelFlag": "--model <id>", "effortFlag": "--effort <level>",
|
|
162
|
+
"models": [ { "id": "model-b", "efforts": ["low", "medium", "high"], "pricing": "included" } ] }
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Here the first pick is `low` and steering says not to exhaust Claude, so choose
|
|
168
|
+
the second pick: `codex`, `model-b`, effort `medium`.
|
|
169
|
+
|
|
170
|
+
## Limits
|
|
171
|
+
|
|
172
|
+
- Grok has only a weekly window. `FTOWN_QUOTA_GROK_NO_REFRESH=1` skips its hidden
|
|
173
|
+
refresh and uses the last logged value.
|
|
174
|
+
- opencode lists only its subscription providers by default. Override with
|
|
175
|
+
`FTOWN_QUOTA_OPENCODE_PROVIDERS=a,b`.
|
|
176
|
+
- The tool does not rank models by capability. The owner's tiers and your
|
|
177
|
+
judgment decide.
|