ftown 0.25.2 → 0.26.0
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/coordination/board.d.ts +12 -0
- package/dist/coordination/board.js +240 -0
- package/dist/coordination/board.js.map +1 -0
- package/dist/coordination/card-store.d.ts +9 -0
- package/dist/coordination/card-store.js +188 -0
- package/dist/coordination/card-store.js.map +1 -0
- package/dist/coordination/contract.d.ts +236 -0
- package/dist/coordination/contract.js +63 -0
- package/dist/coordination/contract.js.map +1 -0
- package/dist/coordination/format.d.ts +5 -0
- package/dist/coordination/format.js +60 -0
- package/dist/coordination/format.js.map +1 -0
- package/dist/coordination/tree-events.d.ts +31 -0
- package/dist/coordination/tree-events.js +226 -0
- package/dist/coordination/tree-events.js.map +1 -0
- package/dist/coordination/wiring.d.ts +48 -0
- package/dist/coordination/wiring.js +143 -0
- package/dist/coordination/wiring.js.map +1 -0
- package/dist/coordination-cli.d.ts +34 -0
- package/dist/coordination-cli.js +460 -0
- package/dist/coordination-cli.js.map +1 -0
- package/dist/ftown-cli.js +12 -2
- package/dist/ftown-cli.js.map +1 -1
- package/dist/index.js +33 -7
- package/dist/index.js.map +1 -1
- package/dist/local-api-server.d.ts +6 -1
- package/dist/local-api-server.js +282 -5
- package/dist/local-api-server.js.map +1 -1
- package/dist/mail-delivery.d.ts +16 -2
- package/dist/mail-delivery.js +331 -77
- package/dist/mail-delivery.js.map +1 -1
- package/dist/mail-store.d.ts +7 -0
- package/dist/mail-store.js +71 -1
- package/dist/mail-store.js.map +1 -1
- package/dist/pull-request-events.d.ts +5 -0
- package/dist/pull-request-events.js +21 -1
- package/dist/pull-request-events.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 +24 -2
- package/dist/security/bridge/permissions.js.map +1 -1
- package/dist/types.d.ts +7 -3
- package/dist/wire-types.d.ts +17 -1
- package/dist/wire-types.js +1 -1
- package/dist/wire-types.js.map +1 -1
- package/package.json +3 -2
- package/skills/ftown/SKILL.md +31 -5
- package/skills/ftown/references/orchestrator.md +17 -7
- package/skills/ftown/references/quota.md +177 -0
- package/skills/ftown/references/sessions.md +45 -3
package/dist/wire-types.d.ts
CHANGED
|
@@ -50,8 +50,23 @@ export interface Session {
|
|
|
50
50
|
/** Historical automation provenance; new sessions cannot set it. */
|
|
51
51
|
loopId?: string;
|
|
52
52
|
usage?: SessionUsage;
|
|
53
|
+
card?: {
|
|
54
|
+
state: string;
|
|
55
|
+
headline: string;
|
|
56
|
+
progress?: {
|
|
57
|
+
done: number;
|
|
58
|
+
total: number;
|
|
59
|
+
};
|
|
60
|
+
blockedOn?: {
|
|
61
|
+
kind: string;
|
|
62
|
+
ref?: string;
|
|
63
|
+
text: string;
|
|
64
|
+
};
|
|
65
|
+
next?: string;
|
|
66
|
+
updatedAt: string;
|
|
67
|
+
};
|
|
53
68
|
}
|
|
54
|
-
export type MailType = 'message' | 'task' | 'result' | 'escalation';
|
|
69
|
+
export type MailType = 'message' | 'task' | 'result' | 'escalation' | 'fyi';
|
|
55
70
|
export declare const MAIL_TYPES: readonly MailType[];
|
|
56
71
|
/** Per-session inbox message, as returned by GET/POST /api/sessions/:id/inbox. */
|
|
57
72
|
export interface MailMessage {
|
|
@@ -65,6 +80,7 @@ export interface MailMessage {
|
|
|
65
80
|
body: string;
|
|
66
81
|
deliveredAt?: string;
|
|
67
82
|
deliveredVia?: string;
|
|
83
|
+
nudgedAt?: string;
|
|
68
84
|
}
|
|
69
85
|
export declare const AUTOMATION_REMOVED_CODE: "automation_removed";
|
|
70
86
|
export declare const AUTOMATION_REMOVED_MESSAGE = "Recurring loops and factory automation have been removed";
|
package/dist/wire-types.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Shared wire shapes for the in-process CLI runtime and local bridge API.
|
|
2
|
-
export const MAIL_TYPES = ['message', 'task', 'result', 'escalation'];
|
|
2
|
+
export const MAIL_TYPES = ['message', 'task', 'result', 'escalation', 'fyi'];
|
|
3
3
|
export const AUTOMATION_REMOVED_CODE = 'automation_removed';
|
|
4
4
|
export const AUTOMATION_REMOVED_MESSAGE = 'Recurring loops and factory automation have been removed';
|
|
5
5
|
/**
|
package/dist/wire-types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wire-types.js","sourceRoot":"","sources":["../src/wire-types.ts"],"names":[],"mappings":"AAAA,0EAA0E;
|
|
1
|
+
{"version":3,"file":"wire-types.js","sourceRoot":"","sources":["../src/wire-types.ts"],"names":[],"mappings":"AAAA,0EAA0E;AA6D1E,MAAM,CAAC,MAAM,UAAU,GAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;AAiBlG,MAAM,CAAC,MAAM,uBAAuB,GAAG,oBAA6B,CAAC;AACrE,MAAM,CAAC,MAAM,0BAA0B,GAAG,0DAA0D,CAAC;AAErG;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAC,UAAmB;IAC9C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,iBAAiB,CAAC,CAAc;IAC9C,OAAO,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;AACpE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ftown",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "CLI bridge for ftown — generic PTY-over-Centrifugo relay",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"ftown": "dist/ftown-cli.js",
|
|
10
10
|
"ftown-harness": "dist/harness-cli.js",
|
|
11
11
|
"ftown-env": "dist/ftown-env-cli.js",
|
|
12
|
+
"ftown-quota": "dist/quota-cli.js",
|
|
12
13
|
"ftown-sessions": "bin/ftown-sessions"
|
|
13
14
|
},
|
|
14
15
|
"files": [
|
|
@@ -72,5 +73,5 @@
|
|
|
72
73
|
"overrides": {
|
|
73
74
|
"qs": "6.16.1"
|
|
74
75
|
},
|
|
75
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "033b06c892db214c1104779f68ef4f36e3c567f8"
|
|
76
77
|
}
|
package/skills/ftown/SKILL.md
CHANGED
|
@@ -51,6 +51,8 @@ ftown sessions preview --add ./extra.html
|
|
|
51
51
|
ftown sessions preview --remove notes.md
|
|
52
52
|
ftown sessions preview --clear
|
|
53
53
|
ftown sessions preview-reply --message "The preview is ready."
|
|
54
|
+
ftown status set --state working --headline "Reviewing the API client" --progress 0/1
|
|
55
|
+
ftown board
|
|
54
56
|
ftown harness mail send <session-id> --type task "review the API client"
|
|
55
57
|
ftown harness mail read
|
|
56
58
|
ftown env --help
|
|
@@ -60,7 +62,8 @@ ftown start --help
|
|
|
60
62
|
|
|
61
63
|
Read `references/sessions.md` for the session, mail and terminal command
|
|
62
64
|
reference. Read `references/orchestrator.md` for practical worker coordination
|
|
63
|
-
examples.
|
|
65
|
+
examples. Read `references/quota.md` before choosing a CLI, model and effort for delegated
|
|
66
|
+
work (`ftown quota --json`). Each command group also has `--help`.
|
|
64
67
|
|
|
65
68
|
`ftown sessions preview <path...>` registers up to 12 files in the current
|
|
66
69
|
session's working directory for the dashboard, in this order. Kind is by
|
|
@@ -94,10 +97,33 @@ ftown harness mail send --parent --type escalation "Blocked: need the API contra
|
|
|
94
97
|
```
|
|
95
98
|
|
|
96
99
|
Mail arrives as `[ftown mail]` context through harness hooks/extensions where
|
|
97
|
-
available.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
available. Mail is for directed instructions (`--type task`), results
|
|
101
|
+
(`--type result`) and escalations (`--type escalation`). Use `--type fyi` for
|
|
102
|
+
non-urgent notes; `fyi` never wakes the recipient. Progress and status go on
|
|
103
|
+
your card (below), never as mail. Each new batch of mail nudges the recipient
|
|
104
|
+
at most once; un-read mail stays in the inbox — read it with
|
|
105
|
+
`ftown harness mail read`. Prefer mail for agent communication; use terminal
|
|
106
|
+
key injection only when the task needs it. Inspect peers with `ftown board`
|
|
107
|
+
and `ftown sessions list`.
|
|
108
|
+
|
|
109
|
+
## Status and board
|
|
110
|
+
|
|
111
|
+
Keep your card current with `ftown status set` at meaningful transitions —
|
|
112
|
+
starting, becoming blocked, finishing — not every turn. Set state
|
|
113
|
+
(`working`, `blocked`, `waiting_review`, `done`, `failed`), a short headline,
|
|
114
|
+
progress and any blocker. Writing a card wakes nobody. Parents read
|
|
115
|
+
`ftown board` (one line per child) instead of screening quiet workers, and
|
|
116
|
+
wait with `ftown board --wait --until any-done|any-blocked|any-ready` or
|
|
117
|
+
`ftown events --wait`. Idle workers show on the board and as an `idle` event.
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
ftown status set --state working --headline "Implementing the card store" --progress 1/4
|
|
121
|
+
ftown status set --state blocked --headline "Need the API contract" --on parent --text "Waiting on the contract decision"
|
|
122
|
+
ftown status set --state done --headline "Card store shipped; checks green"
|
|
123
|
+
ftown board
|
|
124
|
+
ftown board --wait --until any-done --timeout 300
|
|
125
|
+
ftown events --wait
|
|
126
|
+
```
|
|
101
127
|
|
|
102
128
|
## Human attention and pull requests
|
|
103
129
|
|
|
@@ -11,20 +11,30 @@ bounded task, clear writable files and acceptance checks; save the returned
|
|
|
11
11
|
set it when the task calls for a different harness. Provider flavors require a
|
|
12
12
|
bridge-host token configured with `ftown env set <flavor>`.
|
|
13
13
|
|
|
14
|
+
Before picking a CLI, model and effort for delegated work, run `ftown quota --json`
|
|
15
|
+
and follow the decision procedure in `quota.md` (owner tiers first). Pass the
|
|
16
|
+
choice as `--shell <provider>`; add `--model <id>` only with an id from that
|
|
17
|
+
harness's model list. Never route to `exhausted`.
|
|
18
|
+
|
|
14
19
|
```bash
|
|
15
20
|
ftown sessions list
|
|
16
21
|
ftown sessions create --parent --workdir /path/to/repo --name review-auth \
|
|
17
22
|
--prompt "Review auth; read-only. Report concrete findings and validation."
|
|
18
|
-
ftown
|
|
19
|
-
ftown
|
|
23
|
+
ftown board --wait --until any-done --timeout 300
|
|
24
|
+
ftown board
|
|
20
25
|
ftown harness mail send <worker-id> --type task "Check the expired-token case too"
|
|
21
|
-
ftown sessions tell --children "Pause and report status"
|
|
22
26
|
```
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
Coordinate in a loop: spawn children, wait with
|
|
29
|
+
`ftown board --wait --until any-done --timeout 300` (or `any-blocked`,
|
|
30
|
+
`any-ready`, `all-done`; `ftown events --wait` waits for the next event), act
|
|
31
|
+
on the board and mail, then repeat until every child is done. Children keep
|
|
32
|
+
their cards current; progress goes on the card, never as mail. Use
|
|
33
|
+
`ftown sessions screen <worker-id> --limit 100` only to investigate terminal
|
|
34
|
+
detail. Mail handles directed instructions, results and escalations; read it
|
|
35
|
+
with `ftown harness mail read`. Each new batch nudges the recipient at most
|
|
36
|
+
once, and a nudge may append a one-line digest of child status. Parallel tasks
|
|
37
|
+
need disjoint write ownership and serialized shared resources.
|
|
28
38
|
|
|
29
39
|
After accepting a worker's result, request any concrete follow-up before
|
|
30
40
|
explicit cleanup with `ftown sessions remove <worker-id>`.
|
|
@@ -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.
|
|
@@ -51,6 +51,43 @@ ftown sessions archive
|
|
|
51
51
|
ftown sessions revive <session-id>
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
## Status, board and events
|
|
55
|
+
|
|
56
|
+
Each session has a card: state (`working`, `blocked`, `waiting_review`,
|
|
57
|
+
`done`, `failed`), headline, optional progress, blocker and next step. Keep
|
|
58
|
+
your own card current at meaningful transitions, not every turn. Writing a
|
|
59
|
+
card wakes nobody. The target defaults to `FTOWN_SESSION_ID`; `--session-id
|
|
60
|
+
<id>` selects another session.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Print my card
|
|
64
|
+
ftown status [--json] [--session-id <id>]
|
|
65
|
+
|
|
66
|
+
# Update my card (omitted fields unchanged; first write needs --state and --headline)
|
|
67
|
+
ftown status set [--state <s>] [--headline <t>] [--progress <d>/<t>|--no-progress] \
|
|
68
|
+
[--on human|parent|external|session:<id>] [--text <t>] [--next <t>|--no-next] [--session-id <id>]
|
|
69
|
+
|
|
70
|
+
# Remove my card
|
|
71
|
+
ftown status clear [--session-id <id>]
|
|
72
|
+
|
|
73
|
+
# One line per child of my tree
|
|
74
|
+
ftown board [--json] [--since <n>] [--ready] [--all] [--session-id <id>]
|
|
75
|
+
|
|
76
|
+
# Wait until a board condition holds
|
|
77
|
+
ftown board [--wait --until any-change|any-done|any-blocked|all-done|any-ready [--timeout <s≤300>]] [--session-id <id>]
|
|
78
|
+
|
|
79
|
+
# Tree events for my tree (status, attention, pr, preview, exit, idle, result, mail)
|
|
80
|
+
ftown events [--json] [--since <n>] [--limit <n>] [--wait [--timeout <s≤300>]] [--session-id <id>]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`--ready` lists only children whose PR checks passed and who are not done;
|
|
84
|
+
`--all` includes archived/completed children; `--since <n>` limits the board
|
|
85
|
+
to children with events after that cursor (the board prints its cursor).
|
|
86
|
+
Pass the cursor back as `--since` to see only what changed.
|
|
87
|
+
|
|
88
|
+
Exit codes for `status`, `board` and `events`: 0 ok, 1 error, 2 usage,
|
|
89
|
+
3 wait timed out with the condition unmet.
|
|
90
|
+
|
|
54
91
|
## Preview session files
|
|
55
92
|
|
|
56
93
|
```bash
|
|
@@ -213,8 +250,12 @@ reports the conversation id and delivers mail at turn end.
|
|
|
213
250
|
Grok and Antigravity hooks do not run in the interactive TUI until the folder
|
|
214
251
|
has been trusted in that CLI's own trust prompt; the owner answers it once per
|
|
215
252
|
folder, and ftown does not bypass it.
|
|
216
|
-
Cursor and shell sessions rely on
|
|
217
|
-
mail read` instead.
|
|
253
|
+
Cursor and shell sessions rely on a one-line nudge to run `ftown harness
|
|
254
|
+
mail read` instead. Each new batch of mail nudges the recipient at most once;
|
|
255
|
+
un-read mail stays in the inbox. Mail types are `message`, `task`, `result`,
|
|
256
|
+
`escalation` and `fyi`; `fyi` is for non-urgent notes and never wakes the
|
|
257
|
+
recipient. Progress and status go on the session card (see above), never as
|
|
258
|
+
mail.
|
|
218
259
|
|
|
219
260
|
```bash
|
|
220
261
|
# Tell a specific session
|
|
@@ -265,7 +306,8 @@ ftown sessions list
|
|
|
265
306
|
ftown sessions create --prompt "Run tests and report" --workdir "$PWD" --parent
|
|
266
307
|
# -> note session.id from JSON
|
|
267
308
|
|
|
268
|
-
ftown
|
|
309
|
+
ftown board --wait --until any-done --timeout 300
|
|
310
|
+
ftown board
|
|
269
311
|
ftown sessions grep <child-id> --pattern 'FAIL|Error'
|
|
270
312
|
```
|
|
271
313
|
|