@firatcand/roster 0.1.0 → 0.4.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/README.md +7 -2
- package/bin/roster.js +7092 -1167
- package/data/plan-ceilings.yaml +57 -0
- package/package.json +8 -2
- package/skills/chief-of-staff/SKILL.md +158 -2
- package/templates/hooks/banner.sh +47 -0
- package/templates/scaffold/conventions.md +35 -8
- package/templates/scaffold/dreamer/README.md +1 -1
- package/templates/scaffold/gtm/sdr/README.md +1 -6
- package/templates/scaffold/logs/cron/.gitkeep +1 -0
- package/templates/scaffold/ops/EXPERT.md +5 -5
- package/templates/scaffold/scripts/archive-project.sh +98 -0
- package/templates/scaffold/scripts/audit-agent.sh +299 -0
- package/templates/scaffold/scripts/audit-project.sh +361 -0
- package/templates/scaffold/scripts/audit-repo.sh +240 -0
- package/templates/scaffold/scripts/create-function.sh +267 -0
- package/templates/scaffold/scripts/lib/README.md +6 -1
- package/templates/scaffold/scripts/lib/bindings-prompt.sh +136 -0
- package/templates/scaffold/scripts/lib/functions.sh +17 -5
- package/templates/scaffold/scripts/new-agent-instance.sh +114 -0
- package/templates/scaffold/scripts/new-agent.sh +410 -0
- package/templates/scaffold/scripts/remove-agent-from-project.sh +67 -0
- package/templates/scaffold/scripts/rename-project.sh +118 -0
- package/templates/scaffold/scripts/unarchive-project.sh +115 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Plan-ceiling figures for `roster schedule estimate-usage` (ROS-44 / ADR-0001).
|
|
2
|
+
#
|
|
3
|
+
# Advisory estimates of interactive-session caps published by OpenAI and
|
|
4
|
+
# Anthropic. The CLI never queries vendor APIs — these numbers are read from
|
|
5
|
+
# this file at runtime and compared against projected schedule usage.
|
|
6
|
+
#
|
|
7
|
+
# Update this file as vendors publish new limits. Bump `as_of` per entry and
|
|
8
|
+
# cite the public doc URL. Schema version is immutable at 1 — bump and migrate
|
|
9
|
+
# if the shape ever changes.
|
|
10
|
+
|
|
11
|
+
version: 1
|
|
12
|
+
|
|
13
|
+
plans:
|
|
14
|
+
chatgpt-plus:
|
|
15
|
+
tool: codex
|
|
16
|
+
label: "ChatGPT Plus"
|
|
17
|
+
msgs_per_window: 250
|
|
18
|
+
window_hours: 5
|
|
19
|
+
msgs_per_week: 2100
|
|
20
|
+
source_url: "https://help.openai.com/en/articles/6643017-chatgpt-plus-faq"
|
|
21
|
+
as_of: "2026-05-18"
|
|
22
|
+
|
|
23
|
+
chatgpt-pro:
|
|
24
|
+
tool: codex
|
|
25
|
+
label: "ChatGPT Pro"
|
|
26
|
+
msgs_per_window: 1000
|
|
27
|
+
window_hours: 5
|
|
28
|
+
msgs_per_week: 8400
|
|
29
|
+
source_url: "https://help.openai.com/en/articles/8675309-chatgpt-pro"
|
|
30
|
+
as_of: "2026-05-18"
|
|
31
|
+
|
|
32
|
+
claude-pro:
|
|
33
|
+
tool: claude
|
|
34
|
+
label: "Claude Pro"
|
|
35
|
+
msgs_per_window: 45
|
|
36
|
+
window_hours: 5
|
|
37
|
+
msgs_per_week: 1200
|
|
38
|
+
source_url: "https://support.anthropic.com/en/articles/8324991-about-claude-pro-usage"
|
|
39
|
+
as_of: "2026-05-18"
|
|
40
|
+
|
|
41
|
+
claude-max-5x:
|
|
42
|
+
tool: claude
|
|
43
|
+
label: "Claude Max 5x"
|
|
44
|
+
msgs_per_window: 225
|
|
45
|
+
window_hours: 5
|
|
46
|
+
msgs_per_week: 6000
|
|
47
|
+
source_url: "https://support.anthropic.com/en/articles/9534406-about-claude-max-usage"
|
|
48
|
+
as_of: "2026-05-18"
|
|
49
|
+
|
|
50
|
+
claude-max-20x:
|
|
51
|
+
tool: claude
|
|
52
|
+
label: "Claude Max 20x"
|
|
53
|
+
msgs_per_window: 900
|
|
54
|
+
window_hours: 5
|
|
55
|
+
msgs_per_week: 24000
|
|
56
|
+
source_url: "https://support.anthropic.com/en/articles/9534406-about-claude-max-usage"
|
|
57
|
+
as_of: "2026-05-18"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firatcand/roster",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A CLI that scaffolds a structured multi-agent workspace on top of AI coding tools (Claude Code, Codex CLI, Gemini)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"skills/",
|
|
13
13
|
"agents/",
|
|
14
14
|
"templates/",
|
|
15
|
+
"data/",
|
|
15
16
|
"README.md",
|
|
16
17
|
"LICENSE"
|
|
17
18
|
],
|
|
@@ -23,9 +24,14 @@
|
|
|
23
24
|
"typecheck": "tsc --noEmit",
|
|
24
25
|
"dev": "tsdown --watch",
|
|
25
26
|
"test": "node --test --experimental-strip-types 'test/**/*.test.ts'",
|
|
27
|
+
"test:update-golden": "node --experimental-strip-types scripts/update-golden.ts",
|
|
28
|
+
"test:update-golden:stub": "node --experimental-strip-types scripts/update-golden-stub.ts",
|
|
26
29
|
"smoke": "bash test/smoke.sh",
|
|
27
30
|
"e2e": "bash test/e2e-sdr.sh",
|
|
28
|
-
"
|
|
31
|
+
"e2e:schedule": "bash test/e2e-schedule.sh",
|
|
32
|
+
"perf": "bash test/perf.sh",
|
|
33
|
+
"test:dogfood-scripts": "bash test/new-agent-slash-only.sh && bash test/scripts-parity.sh",
|
|
34
|
+
"probe:claude-url": "bash scripts/probe-claude-url-scheme.sh"
|
|
29
35
|
},
|
|
30
36
|
"keywords": [
|
|
31
37
|
"claude-code",
|
|
@@ -139,7 +139,159 @@ Loop on `revise` until the user types `y` or `cancel`. There is no implicit "loo
|
|
|
139
139
|
|
|
140
140
|
### Phase 5 — Atomic write
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
Transitions from accepted Phase 4 preview (`y`) to files-on-disk. The **agent tree** at `<fn>/<agent>/` (Steps 4–5) is written as a single transaction — either every staged file in the tree lands, or nothing does. The **slash command** at `<repo-root>/.claude/commands/<agent>.md` (Step 6) is a separate post-tree write: it can fail or be interrupted independently and is recovered via `--slash-only` retry rather than rollback.
|
|
143
|
+
|
|
144
|
+
#### Transaction state
|
|
145
|
+
|
|
146
|
+
- `draft: Map<absolute_path, string>` — in-memory file map (every path the write will create, with final content). Built incrementally during Phase 2/3 as fields are populated.
|
|
147
|
+
- `dirs: List<absolute_path>` — directories to create, enumerated explicitly (no implicit ancestors). Listed parent-before-child so the corresponding `rmdir` walk in Step 7 can go deepest-first.
|
|
148
|
+
- `rollback: List<absolute_path>` — every newly-created path (file or directory), appended in creation order. Includes every directory in `dirs`, every file from `draft` once its write is attempted, and nothing else. Drives reverse-order cleanup on failure.
|
|
149
|
+
|
|
150
|
+
#### Step 1 — Pre-write invariant check
|
|
151
|
+
|
|
152
|
+
Run all five invariants from § "Cross-file invariants" against `draft`. On any failure:
|
|
153
|
+
|
|
154
|
+
> Invariant N failed: <specific failure>. Revise the affected section, or `cancel` to abort without writing.
|
|
155
|
+
|
|
156
|
+
Re-enter Phase 3 for the offending section. The atomic-write transaction NEVER proceeds with a tripped invariant — no partial state can leak onto disk.
|
|
157
|
+
|
|
158
|
+
Invariant 2 (step ids match `plans/<plan>.yaml`) is vacuously satisfied when no starter plan was named during Phase 3 — per the Generated file contracts table, `plans/<plan>.yaml` is optional. The check applies only when at least one plan file is staged in `draft`.
|
|
159
|
+
|
|
160
|
+
#### Step 2 — Final user preview
|
|
161
|
+
|
|
162
|
+
Confirm once more: `Write this? (y/revise/cancel)`. Re-render the full Phase 4 preview only if the user typed `revise` since the last render. On `cancel` print `Cancelled. No files written.` and exit. On `y` proceed to Step 3.
|
|
163
|
+
|
|
164
|
+
#### Step 3 — Install SIGINT trap
|
|
165
|
+
|
|
166
|
+
Install a signal handler covering **Steps 4–5 only** (the agent-tree transaction). On Ctrl+C: run the rollback sequence (Step 7) best-effort, then append a Step 8 log entry with `outcome: interrupted` (best-effort — log failure is non-fatal), then exit non-zero. After cleanup, print either:
|
|
167
|
+
|
|
168
|
+
> Interrupted. Rolled back N files. Workspace is clean.
|
|
169
|
+
|
|
170
|
+
or, if cleanup itself partially fails:
|
|
171
|
+
|
|
172
|
+
> Interrupted. Cleanup incomplete — these paths remain on disk:
|
|
173
|
+
> `<path>`
|
|
174
|
+
> `<path>`
|
|
175
|
+
> Remove manually before retrying.
|
|
176
|
+
|
|
177
|
+
Uninstall the trap **before** entering Step 6. Once the agent tree is canonical (i.e., `agent.md` has landed), a SIGINT during Step 6 is treated as a slash-command failure, not as cause for rollback — the agent tree is preserved and the user can recover with `--slash-only` (Step 6 retry guidance).
|
|
178
|
+
|
|
179
|
+
#### Step 4 — Create directory tree
|
|
180
|
+
|
|
181
|
+
Enumerate every directory the transaction creates **explicitly** (no `mkdir -p` shortcut that hides intermediate ancestors from the cleanup walker — Step 7 needs to remove them). Create them one at a time, parent-before-child, appending each to `rollback`:
|
|
182
|
+
|
|
183
|
+
- `<fn>/<agent>/`
|
|
184
|
+
- `<fn>/<agent>/subagents/`
|
|
185
|
+
- `<fn>/<agent>/playbook/`
|
|
186
|
+
- `<fn>/<agent>/logs/`
|
|
187
|
+
- `<fn>/<agent>/.claude/`
|
|
188
|
+
- `<fn>/<agent>/.claude/skills/`
|
|
189
|
+
- `<fn>/<agent>/.claude/plugins/`
|
|
190
|
+
- `<fn>/<agent>/plans/`
|
|
191
|
+
- `<fn>/<agent>/projects/`
|
|
192
|
+
- `<fn>/<agent>/projects/_template/`
|
|
193
|
+
- `<fn>/<agent>/projects/_template/config/`
|
|
194
|
+
- `<fn>/<agent>/projects/_template/playbook/`
|
|
195
|
+
- `<fn>/<agent>/projects/_template/log/`
|
|
196
|
+
- `<fn>/<agent>/projects/_template/log/runs/`
|
|
197
|
+
- `<fn>/<agent>/projects/_template/log/feedback/`
|
|
198
|
+
|
|
199
|
+
If a directory already exists at the moment we try to create it (e.g., racing process, or `<fn>/` exists from a prior function), do NOT append it to `rollback` — pre-existing paths are not ours to delete. Skip and continue. The parent `<fn>/` itself is never in `rollback` for the same reason (it predates this transaction or was created as `<fn>/<agent>/`'s implicit parent — see invariant: if `<fn>/` does not exist, abort the whole transaction before Step 4 and ask the user to register the function via `create-function` first).
|
|
200
|
+
|
|
201
|
+
If a directory creation fails for any other reason (permissions, ENOSPC), skip to Step 7 with `rollback` populated up to the failure point.
|
|
202
|
+
|
|
203
|
+
#### Step 5 — Write files in deterministic order
|
|
204
|
+
|
|
205
|
+
Write each file from `draft`. Append every written path to `rollback` **before** the write begins, so a write-failure mid-byte still leaves the partial file in the cleanup set.
|
|
206
|
+
|
|
207
|
+
Order:
|
|
208
|
+
|
|
209
|
+
1. `<fn>/<agent>/README.md`
|
|
210
|
+
2. `<fn>/<agent>/.mcp.json`
|
|
211
|
+
3. `<fn>/<agent>/.claude/settings.json`
|
|
212
|
+
4. `<fn>/<agent>/subagents/_template.md`
|
|
213
|
+
5. `<fn>/<agent>/subagents/<name>.md` (one per `agent.md ## Subagents` entry; zero files if none named)
|
|
214
|
+
6. `<fn>/<agent>/plans/.gitkeep`
|
|
215
|
+
7. `<fn>/<agent>/plans/<plan>.yaml` (one per plan named in Phase 3; absent in stub mode and when no plan named)
|
|
216
|
+
8. `<fn>/<agent>/projects/_template/config/default.yaml`
|
|
217
|
+
9. `<fn>/<agent>/projects/_template/asset-references.md`
|
|
218
|
+
10. `<fn>/<agent>/playbook/.gitkeep`
|
|
219
|
+
11. `<fn>/<agent>/logs/.gitkeep`
|
|
220
|
+
12. `<fn>/<agent>/.claude/skills/.gitkeep`
|
|
221
|
+
13. `<fn>/<agent>/.claude/plugins/.gitkeep`
|
|
222
|
+
14. `<fn>/<agent>/projects/_template/playbook/.gitkeep`
|
|
223
|
+
15. `<fn>/<agent>/projects/_template/log/runs/.gitkeep`
|
|
224
|
+
16. `<fn>/<agent>/projects/_template/log/feedback/.gitkeep`
|
|
225
|
+
17. `<fn>/<agent>/agent.md` ← **LAST. Canonical contract.**
|
|
226
|
+
|
|
227
|
+
**Why `agent.md` last:** It is the canonical orchestrator contract — the file roster's commands grep for to detect an agent's existence. Writing it last guarantees that any process **keyed off the existence of `agent.md`** observes either no agent or a complete one. A mid-Step-5 crash leaves either no `agent.md` at all, or — after Step 7 rollback — an empty `<fn>/<agent>/` parent that no contract-aware reader will treat as a valid agent.
|
|
228
|
+
|
|
229
|
+
This is a **path-level / discovery-keyed** guarantee, not a process-isolation guarantee. A third party that opens a path mid-write retains an open file descriptor through rollback, and a directory listing of `<fn>/<agent>/` mid-Step-4/5 can show a partial tree (this is why discovery should always key off `agent.md`, never directory enumeration).
|
|
230
|
+
|
|
231
|
+
On any write failure mid-Step-5, skip to Step 7. `rollback` already contains every path attempted, including the partially-written file at the failure point.
|
|
232
|
+
|
|
233
|
+
**Note — divergence from stub mode:** `scripts/new-agent.sh` (stub mode) writes `agent.md` first as a single shell-script side effect; the script is not transactional. Guided mode adopts the safer LAST-ordering to make the canonical-contract invariant hold. The two paths are intentionally different — do not "fix" one to match the other.
|
|
234
|
+
|
|
235
|
+
#### Step 6 — Write slash command (outside rollback root)
|
|
236
|
+
|
|
237
|
+
The SIGINT trap from Step 3 is uninstalled before this step begins. Write `<repo-root>/.claude/commands/<agent>.md`. This path is **outside** `<fn>/<agent>/`, so it is **not** in the `rollback` list — neither a write failure nor a Ctrl+C during Step 6 triggers a rollback of the agent tree.
|
|
238
|
+
|
|
239
|
+
On failure (or SIGINT during Step 6 leaves a partial file), print:
|
|
240
|
+
|
|
241
|
+
> Agent tree at `<fn>/<agent>/` written successfully, but slash command `.claude/commands/<agent>.md` failed: `<error>`. Retry with:
|
|
242
|
+
> `bash scripts/new-agent.sh --slash-only <fn> <agent>`
|
|
243
|
+
|
|
244
|
+
The `--slash-only` flag (added in P4-T05) accepts the same two positional args and writes ONLY the slash command — no other side effects, no prompts. Required because the agent tree is already canonical at this point; re-running the full plan would refuse on the existing directory. Caveats for retry:
|
|
245
|
+
|
|
246
|
+
- If the slash command file already exists at retry time (e.g., partial write from Step 6 failure or SIGINT), `--slash-only` refuses to clobber per P4-T05 acceptance — remove the existing file first, then retry.
|
|
247
|
+
- `--slash-only` does NOT verify that `<fn>/<agent>/agent.md` exists. If the agent tree was rolled back before retry, the slash command will be a dangling pointer. Re-run the full `create-agent` plan instead in that case.
|
|
248
|
+
|
|
249
|
+
#### Step 7 — Rollback (failure path)
|
|
250
|
+
|
|
251
|
+
Triggered by any error in Steps 4–5, or by SIGINT during Steps 4–5 (Step 3 trap). Step 6 failures and Step-6 SIGINT are **not** rollback triggers — they are surfaced for `--slash-only` retry instead.
|
|
252
|
+
|
|
253
|
+
Sequence:
|
|
254
|
+
|
|
255
|
+
1. Walk `rollback` in reverse order (newest first). For each path:
|
|
256
|
+
- If it is a file (or partially-written file), `unlink` it.
|
|
257
|
+
- If it is a directory, `rmdir` it (no `-r`). It will succeed because all of its children were created later than it and have already been removed by this walk. If `rmdir` fails because something unexpected exists (race, manual write), record the path as residual and continue.
|
|
258
|
+
2. After the walk, `<fn>/<agent>/` itself is either gone (if `rollback` included it and the walk reached it) or remains with residual content. Do NOT attempt a recursive delete — if anything remains, it is either pre-existing (not ours) or unexpected (worth surfacing).
|
|
259
|
+
3. Print:
|
|
260
|
+
> Write failed at `<path>`: `<error>`. Rolled back N paths (M files, K directories).
|
|
261
|
+
|
|
262
|
+
If `<fn>/<agent>/` was removed:
|
|
263
|
+
> Workspace is clean.
|
|
264
|
+
|
|
265
|
+
Else:
|
|
266
|
+
> Workspace still contains `<fn>/<agent>/` with N residual paths:
|
|
267
|
+
> `<path>`
|
|
268
|
+
> `<path>`
|
|
269
|
+
> Remove manually before retrying.
|
|
270
|
+
4. Append a Step 8 log entry with `outcome: rollback` and the residual-paths list, then exit non-zero.
|
|
271
|
+
|
|
272
|
+
#### Step 8 — Operation log
|
|
273
|
+
|
|
274
|
+
Always append exactly one log entry per `create-agent` invocation to `chief-of-staff/logs/<YYYY-MM>/operations-<YYYY-MM-DD>.md`. Trigger points:
|
|
275
|
+
|
|
276
|
+
| Operation outcome | When Step 8 fires | `outcome` value |
|
|
277
|
+
| --- | --- | --- |
|
|
278
|
+
| Steps 4–6 all succeed | end of Step 6 | `success` |
|
|
279
|
+
| Step 5/4 write failure | end of Step 7 rollback walk | `rollback` |
|
|
280
|
+
| Step 6 write failure (agent tree canonical, slash failed) | after the user-facing retry message in Step 6 | `partial-slash-failure` |
|
|
281
|
+
| SIGINT during Steps 4–5 | inside the trap, after the Step 7 rollback walk | `interrupted` |
|
|
282
|
+
| SIGINT during Step 6 (agent tree canonical, slash partial) | after Step 6 retry message | `partial-slash-failure` (with a note that the slash file may be partial) |
|
|
283
|
+
|
|
284
|
+
Schema:
|
|
285
|
+
|
|
286
|
+
- `timestamp` (UTC ISO-8601)
|
|
287
|
+
- `plan: create-agent`
|
|
288
|
+
- `mode: guided | stub`
|
|
289
|
+
- `inputs: <fn>, <agent>`
|
|
290
|
+
- `outcome: success | rollback | partial-slash-failure | interrupted`
|
|
291
|
+
- `residual_paths:` (only present when outcome is `rollback` or `interrupted`; empty list if cleanup was complete)
|
|
292
|
+
- `candidate_lessons:` (optional, per § "Lessons protocol")
|
|
293
|
+
|
|
294
|
+
The log file is append-only. If `chief-of-staff/logs/<YYYY-MM>/` doesn't exist, create it during Step 8. This write is **outside** the transaction — a log-write failure does NOT trigger rollback of a successful agent creation; surface a stderr warning instead.
|
|
143
295
|
|
|
144
296
|
## Generated file contracts
|
|
145
297
|
|
|
@@ -149,7 +301,7 @@ Every file the guided plan writes has a per-file content contract. Stub mode pro
|
|
|
149
301
|
| --- | --- | --- |
|
|
150
302
|
| `agent.md` | See per-section disposition below. Populated and grounded fields filled from prose + Phase 3 answers; boilerplate fields filled from `_template/` and `conventions.md`. Zero literal `<placeholder>` strings remain (explicit `TODO: <gap>` markers allowed only where the user deferred during Phase 3). | Identical to `bash scripts/new-agent.sh` output: every grounded/uncertain field carries its `<placeholder>` text verbatim. |
|
|
151
303
|
| `plans/<plan>.yaml` | Created only if the user named at least one plan during Phase 3. Step `id:` fields 1:1 with `agent.md ## Steps` — they cannot drift. Inputs / outputs schemas come from the user's plan description. | `plans/.gitkeep` only. No starter plan file. |
|
|
152
|
-
| `subagents/<name>.md` | One file per name listed in `agent.md ## Subagents`. All **six** required sections present and populated: `Role`, `Inputs`, `Output`, `Tools`, `Boundaries`, `Quality bar`. **Never half-populate a subagent.** If a section cannot be populated from prose / follow-ups, either remove the subagent from `agent.md ## Subagents` entirely or Phase 3 re-asks. | `subagents/_template.md` only. No per-name files. |
|
|
304
|
+
| `subagents/<name>.md` | One file per name listed in `agent.md ## Subagents`. All **six** required sections present and populated: `Role`, `Inputs`, `Output`, `Tools`, `Boundaries`, `Quality bar`. **Never half-populate a subagent.** If a section cannot be populated from prose / follow-ups, either remove the subagent from `agent.md ## Subagents` entirely or Phase 3 re-asks. `subagents/_template.md` is also written byte-for-byte from `_template/` (same as stub mode). | `subagents/_template.md` only. No per-name files. |
|
|
153
305
|
| `.claude/commands/<agent>.md` | `description:` field is a real sentence: ≤ 80 chars, contains no `<` character, and contains no literal `TODO:` substring. The body matches the canonical routing-logic template from `_template/` with `<agent>` and `<function>` substituted. | `description: <function> agent — TODO: fill in description`. Canonical body otherwise unchanged. |
|
|
154
306
|
| `README.md`, `.mcp.json`, `.claude/settings.json`, `projects/_template/**`, every `.gitkeep` | Identical to stub mode — byte-for-byte. These files do not vary by mode. | (canonical) |
|
|
155
307
|
|
|
@@ -209,6 +361,10 @@ Never write directly to `chief-of-staff/playbook/` during operations. The user m
|
|
|
209
361
|
- **YAML/JSON parse error in audit** → report as failure with the line number from the audit script
|
|
210
362
|
- **Confirmation gate denied** → abort cleanly, no changes
|
|
211
363
|
- **Partial failure mid-operation** → scripts handle their own rollback. If a script reports partial state, surface exactly what state the repo is in and what to do next.
|
|
364
|
+
- **Atomic write rollback ran** (guided mode, Steps 4–5 failure) → all `rollback` paths deleted, parent `<fn>/<agent>/` removed if empty. Surface residual paths if any deletion failed; exit non-zero.
|
|
365
|
+
- **SIGINT during atomic write** → trap runs Step 7 best-effort; partial cleanup state disclosed. User must remove residual paths before retrying.
|
|
366
|
+
- **Slash command failed after agent tree success** (Step 6) → agent tree is canonical and kept. Surface the failure with the `--slash-only <fn> <agent>` retry command. Not a rollback trigger.
|
|
367
|
+
- **Operation log write failed after successful agent creation** (Step 8) → log a warning to stderr; do NOT roll back the agent. Logs are best-effort and outside the transaction.
|
|
212
368
|
|
|
213
369
|
## What this skill does NOT do
|
|
214
370
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# roster:hitl-banner:v2 — SessionStart hook for Claude Code and Codex CLI.
|
|
3
|
+
#
|
|
4
|
+
# 1. (ROS-42) If `roster` is on PATH, run `roster pending sync --silent` with
|
|
5
|
+
# a 5s timeout to synthesize HITL items from any failed-fire signals
|
|
6
|
+
# (.exit non-zero + STALE detections). Silent on success, silent on
|
|
7
|
+
# skip-because-no-roster, silent on timeout.
|
|
8
|
+
# 2. Count pending HITL items in $PWD/roster/<function>/pending/*.md and
|
|
9
|
+
# print one banner line if count > 0. Silent when count is 0.
|
|
10
|
+
#
|
|
11
|
+
# Self-contained POSIX shell — Step 1 is best-effort opt-in, never blocks
|
|
12
|
+
# the session. Step 2 stays under the <200ms latency budget (p50 ~25ms).
|
|
13
|
+
#
|
|
14
|
+
# Installed by `roster hooks install` to:
|
|
15
|
+
# ~/.claude/hooks/roster-banner.sh
|
|
16
|
+
# ~/.codex/hooks/roster-banner.sh
|
|
17
|
+
|
|
18
|
+
set -u
|
|
19
|
+
|
|
20
|
+
# Run only inside roster workspaces. Quiet exit otherwise so non-roster
|
|
21
|
+
# sessions get zero overhead beyond shell startup.
|
|
22
|
+
[ -d "$PWD/roster" ] || exit 0
|
|
23
|
+
|
|
24
|
+
# Step 1: failed-fire synthesis (best-effort).
|
|
25
|
+
# Requires both `roster` on PATH AND a `timeout` binary. Skip silently
|
|
26
|
+
# otherwise — better to miss a sync than to block SessionStart on a slow
|
|
27
|
+
# workspace (codex review impl-pass: an unbounded fallback ran `roster
|
|
28
|
+
# pending sync` with no time cap; if disk was slow the user's first Claude
|
|
29
|
+
# Code message could be delayed seconds). Doctor remains the deterministic
|
|
30
|
+
# way to surface failed fires for users without a timeout binary.
|
|
31
|
+
if command -v roster >/dev/null 2>&1; then
|
|
32
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
33
|
+
timeout 5 roster pending sync --silent --cwd "$PWD" >/dev/null 2>&1 || true
|
|
34
|
+
elif command -v gtimeout >/dev/null 2>&1; then
|
|
35
|
+
gtimeout 5 roster pending sync --silent --cwd "$PWD" >/dev/null 2>&1 || true
|
|
36
|
+
fi
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# Step 2: banner. `find … | wc -l` returns 0 on empty, never errors on
|
|
40
|
+
# absent subdirs thanks to `-path` matching against a non-existent prefix
|
|
41
|
+
# being a no-op (the explicit `2>/dev/null` covers any read-permission
|
|
42
|
+
# edge case).
|
|
43
|
+
count=$(find "$PWD/roster" -mindepth 3 -maxdepth 3 -type f -name '*.md' -path '*/pending/*.md' 2>/dev/null | wc -l | tr -d ' ')
|
|
44
|
+
|
|
45
|
+
if [ "${count:-0}" -gt 0 ]; then
|
|
46
|
+
printf '⚠ %s pending HITL items — run `roster review`\n' "$count"
|
|
47
|
+
fi
|
|
@@ -9,7 +9,7 @@ Full reference. CLAUDE.md is the short behavioral guide loaded at session start;
|
|
|
9
9
|
3. **Tooling is scoped where it belongs.** Universal MCPs/skills/plugins at root. Agent-scoped at the agent. No per-project tooling — projects share the agent's tools.
|
|
10
10
|
4. **Files are the memory layer.** No vector DB, no embedding store. Markdown + YAML + Git.
|
|
11
11
|
5. **Project-scoped lessons override global on conflict.** Local always wins at runtime.
|
|
12
|
-
6. **Schedules are stateless.**
|
|
12
|
+
6. **Schedules are stateless.** A native local scheduler (Claude Desktop Scheduled Tasks, Codex app Automations, or a Codex cron entry installed via `roster schedule install --via cron`) fires a fresh CLI session that loads `CONTEXT.md` and invokes the `roster-orchestrator` skill. All model usage draws from the user's interactive subscription — no Agent SDK, no headless API keys.
|
|
13
13
|
7. **The dreamer learns; agents act.** Reinforcement is a separate, deliberate process. Live agents don't update playbooks.
|
|
14
14
|
|
|
15
15
|
## Directory map
|
|
@@ -565,15 +565,42 @@ Approval expires after 24h by default. Workflows specify own TTL if different.
|
|
|
565
565
|
|
|
566
566
|
## Schedules
|
|
567
567
|
|
|
568
|
-
|
|
568
|
+
Schedules fire from a native local desktop scheduler. Each fire spawns a fresh CLI session in the workspace that loads `CONTEXT.md` and invokes the `roster-orchestrator` skill; the orchestrator dispatches the agent's subagent via the tool's native primitive (Claude `Task` tool or Codex agent invocation). No `claude -p`, no Anthropic Agent SDK, no programmatic API keys — all model usage draws from the user's interactive Claude Pro/Max or ChatGPT Plus/Pro subscription. `roster doctor` enforces this.
|
|
569
569
|
|
|
570
|
-
|
|
571
|
-
2. Invoke a wrapper at `scripts/cron/wrappers/<job>.sh`
|
|
572
|
-
3. Wrapper sets up env, calls `claude -p "<prompt>"` with the right cwd (typically inside an agent's project instance)
|
|
573
|
-
4. stdout/stderr → `logs/cron/<job>-<YYYY-MM-DD>.log`
|
|
574
|
-
5. Run output → the agent's instance `log/runs/` as normal
|
|
570
|
+
Canonical entry point:
|
|
575
571
|
|
|
576
|
-
|
|
572
|
+
```sh
|
|
573
|
+
roster schedule install <function>/<agent> <plan> \
|
|
574
|
+
--cron "<expr>" --tool claude|codex [--via cron]
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
The first two positional arguments are `<function>/<agent>` (e.g., `gtm/sdr`) and the plan path within that agent. `--cron` and `--tool` are required; `--via` defaults to `ui-handoff`, `--name` defaults to `<agent>-<plan>`, `--project` defaults to `_demo`. The command writes one entry per schedule to `roster/<function>/schedules.yaml` and renders a tool-specific install artifact:
|
|
578
|
+
|
|
579
|
+
- `--tool claude` — emits `.roster/schedule-specs/<name>.claude.fields.md` for paste-in to Claude Code's Desktop Scheduled Tasks UI. Programmatic install is tracked upstream at [anthropics/claude-code#41364](https://github.com/anthropics/claude-code/issues/41364); until it lands, hand-off is markdown, not JSON.
|
|
580
|
+
- `--tool codex` (default `--via ui-handoff`) — emits `.roster/schedule-specs/<name>.codex.fields.md` for paste-in to the Codex desktop Automations UI.
|
|
581
|
+
- `--tool codex --via cron` — installs a hardened crontab line directly (wrapped by `env -i` for environment scrubbing, with a subscription-attestation preflight). Codex-only; refused on Windows.
|
|
582
|
+
|
|
583
|
+
Each run:
|
|
584
|
+
|
|
585
|
+
1. Loads `CONTEXT.md` (via the `CLAUDE.md` or `AGENTS.md` symlink)
|
|
586
|
+
2. Invokes the `roster-orchestrator` skill
|
|
587
|
+
3. Orchestrator dispatches the agent subagent in isolated context (nested subagents allowed)
|
|
588
|
+
4. Run output → the agent's instance `log/runs/` as normal
|
|
589
|
+
5. HITL items → `roster/<function>/pending/` — chat sessions surface a banner on next start
|
|
590
|
+
6. Exits
|
|
591
|
+
|
|
592
|
+
### Failure observability
|
|
593
|
+
|
|
594
|
+
Two complementary signals catch the cases where a fire doesn't complete cleanly:
|
|
595
|
+
|
|
596
|
+
- **`roster/<function>/state.md`** — orchestrator skill appends one line per fire (`<utc-iso> | <function>/<agent>/<plan>/<project> | success|failed`). This is the *agent-level* signal: it requires the orchestrator to actually run to completion.
|
|
597
|
+
- **`logs/cron/<name>.exit`** — for codex `--via cron` schedules, the wrapper records the process exit code (1-3 byte ASCII integer) independently of the agent. Non-zero here means cron fired but the codex process exited with an error.
|
|
598
|
+
|
|
599
|
+
`roster doctor` (the `Scheduling fires` section) cross-references both. `roster pending sync` synthesizes `roster/<function>/pending/error-<id>.md` items from any non-zero `.exit` or STALE detection (last run older than expected next-fire + 2h grace). The SessionStart hook runs `pending sync` automatically before counting items, so a failed fire surfaces in the very next chat session — no manual step required.
|
|
600
|
+
|
|
601
|
+
Optional: add `capture_events: true` to a codex via-cron entry to also capture the `codex exec --json` event stream at `logs/cron/<name>.events.jsonl` (stdout split from log).
|
|
602
|
+
|
|
603
|
+
See [ADR-0001: Scheduling architecture](https://github.com/firatcand/roster/blob/main/docs/adr/0001-scheduling-architecture.md) for the rationale and rejected alternatives.
|
|
577
604
|
|
|
578
605
|
## External-action gates
|
|
579
606
|
|
|
@@ -17,7 +17,7 @@ Cross-domain pattern detection matters. A lesson observed in Twitter automation
|
|
|
17
17
|
|
|
18
18
|
## Invocation
|
|
19
19
|
|
|
20
|
-
Nightly via
|
|
20
|
+
Nightly via the native desktop scheduler. Register with `roster schedule install` — each fire spawns a fresh CLI session in the workspace, loads `CONTEXT.md`, invokes the `roster-orchestrator` skill, and dispatches the dreamer in isolated subagent context. See `conventions.md` § Schedules and [ADR-0001](../../docs/adr/0001-scheduling-architecture.md) for the model. Subscription-billed only; `claude -p` and the Anthropic Agent SDK are banned and enforced by `roster doctor`.
|
|
21
21
|
|
|
22
22
|
On-demand from a session: "Run the dreamer on the last week's outreach runs across all projects."
|
|
23
23
|
|
|
@@ -24,12 +24,7 @@ claude
|
|
|
24
24
|
|
|
25
25
|
Claude reads agent.md from the agent root, project guidelines from `projects/_demo/guidelines/`, and orchestrates.
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
cd /path/to/agent-team
|
|
31
|
-
claude -p "$(cat scripts/cron/wrappers/_demo-outreach-daily-prompt.txt)"
|
|
32
|
-
```
|
|
27
|
+
For scheduled runs, register the schedule with the native desktop scheduler via `roster schedule install` — see the Phase 2.5 scheduling guide. The subscription-only ban on `claude -p` and the Anthropic Agent SDK is enforced by `roster doctor`.
|
|
33
28
|
|
|
34
29
|
## Configuration
|
|
35
30
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Cron log directory
|
|
@@ -11,7 +11,7 @@ Ops advisor for an early-stage solo founder running an agent team. Cover automat
|
|
|
11
11
|
|
|
12
12
|
## Scope
|
|
13
13
|
|
|
14
|
-
- **Critique**: Audit `
|
|
14
|
+
- **Critique**: Audit `roster/<function>/schedules.yaml`, `.roster/schedule-specs/`, agent `config/default.yaml` files, `.env` patterns, and ops-related project guidelines when they exist. State the principle being violated. Score risk: data loss > silent failure > cost > polish.
|
|
15
15
|
- **Generate guidelines**: Produce or refine ops-related guideline files when a project demands them — `projects/<project>/guidelines/ops-runbook.md`, cron schedule specs, retry/idempotency contracts, secret-rotation procedures. Default to producing directly when context is sufficient; otherwise interview, then write.
|
|
16
16
|
- **Guide**: Scheduling decisions, secrets management, deployment patterns, observability strategy, failure-mode reasoning. Strategic output — files only when the task asks for substrate.
|
|
17
17
|
|
|
@@ -22,16 +22,16 @@ You do **NOT** produce tactical artifacts (specific cron wrapper shell scripts,
|
|
|
22
22
|
On invocation, read in this order:
|
|
23
23
|
|
|
24
24
|
1. `projects/<project>/CLAUDE.md` — project identity and what runs against it
|
|
25
|
-
2. `
|
|
25
|
+
2. `roster/<function>/schedules.yaml` and `.roster/schedule-specs/` — current automation surface (Phase 2.5 native-scheduler model; see `conventions.md` § Schedules and [ADR-0001](../../docs/adr/0001-scheduling-architecture.md))
|
|
26
26
|
3. The relevant agent's `agent.md` and `config/default.yaml` — tool bindings, schedules, caps
|
|
27
27
|
4. `projects/<project>/state.md` — current focus
|
|
28
|
-
5. `logs/cron/*` for recent failures, if a reliability question
|
|
28
|
+
5. `logs/cron/*` for recent `roster schedule install --tool codex --via cron` failures, if a reliability question
|
|
29
29
|
|
|
30
30
|
Identify gaps. Ask only about gaps. Don't re-ask what's already in substrate. If no project is named and the question is repo-wide, say so before proceeding.
|
|
31
31
|
|
|
32
32
|
## What you cover
|
|
33
33
|
|
|
34
|
-
- Scheduling (
|
|
34
|
+
- Scheduling (native desktop scheduler via `roster schedule install`, the `roster schedule install --tool codex --via cron` crontab path, GitHub Actions scheduled workflows)
|
|
35
35
|
- Secrets management (`.env`, env-var conventions, rotation, SOPS or similar when justified)
|
|
36
36
|
- Deployment patterns (script-based, GitHub Actions, manual checklists)
|
|
37
37
|
- Observability (`logs/cron/`, structured logging, alerting thresholds, "did it run" verification)
|
|
@@ -62,7 +62,7 @@ When a task spans skills (e.g., "design the cron + monitoring + alert chain for
|
|
|
62
62
|
## Behavior rules
|
|
63
63
|
|
|
64
64
|
- **Idempotency first.** Every operation must be safe to re-run. If it isn't, name the guard.
|
|
65
|
-
- **Observability is non-negotiable.** If you can't tell whether it ran, it didn't.
|
|
65
|
+
- **Observability is non-negotiable.** If you can't tell whether it ran, it didn't. For `--via cron` installs (Codex-only — `roster schedule install --tool codex --via cron`), stdout/stderr lands in `logs/cron/<job>.log` per `conventions.md` § Schedules. For UI-handoff installs (Claude Scheduled Tasks, Codex Automations), the scheduler owns the log surface — check the host app's run history.
|
|
66
66
|
- **Cost-aware.** Name the cost of every recommendation — dollars, time, on-call burden.
|
|
67
67
|
- **Name failure modes.** Don't ship a recommendation without stating what happens when it fails.
|
|
68
68
|
- **Stay in your lane.** Reusable substrate and patterns. One-off incident response and per-run remediations are agent work, not expert work.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# archive-project.sh — moves a project and all its agent instances to _archive/
|
|
3
|
+
# Usage: bash scripts/archive-project.sh <project> [reason]
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
if [ $# -lt 1 ]; then
|
|
8
|
+
echo "Usage: $0 <project> [reason]"
|
|
9
|
+
exit 1
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
PROJECT="$1"
|
|
13
|
+
REASON="${2:-}"
|
|
14
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
15
|
+
PROJECT_DIR="$ROOT/projects/$PROJECT"
|
|
16
|
+
|
|
17
|
+
if [ ! -d "$PROJECT_DIR" ]; then
|
|
18
|
+
echo "ERROR: Project '$PROJECT' not found at $PROJECT_DIR"
|
|
19
|
+
exit 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
DATE=$(date +%Y-%m-%d)
|
|
23
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
24
|
+
|
|
25
|
+
# Find all agent instances for this project
|
|
26
|
+
INSTANCES=()
|
|
27
|
+
while IFS= read -r path; do
|
|
28
|
+
INSTANCES+=("$path")
|
|
29
|
+
done < <(find "$ROOT" -type d -path "*/projects/$PROJECT" -not -path "*/_template/*" -not -path "*/_archive/*" 2>/dev/null | grep -v "^$ROOT/projects/$PROJECT$" || true)
|
|
30
|
+
|
|
31
|
+
# Determine archive suffix (handle same-day re-archiving)
|
|
32
|
+
SUFFIX="$DATE"
|
|
33
|
+
COUNTER=2
|
|
34
|
+
while [ -d "$ROOT/_archive/projects/$PROJECT-$SUFFIX" ]; do
|
|
35
|
+
SUFFIX="$DATE-$COUNTER"
|
|
36
|
+
COUNTER=$((COUNTER + 1))
|
|
37
|
+
done
|
|
38
|
+
|
|
39
|
+
echo "Archiving project: $PROJECT (suffix: $SUFFIX)"
|
|
40
|
+
|
|
41
|
+
# Create archive root
|
|
42
|
+
mkdir -p "$ROOT/_archive/projects"
|
|
43
|
+
|
|
44
|
+
# Move project root
|
|
45
|
+
mv "$PROJECT_DIR" "$ROOT/_archive/projects/$PROJECT-$SUFFIX"
|
|
46
|
+
echo " Moved: projects/$PROJECT/ → _archive/projects/$PROJECT-$SUFFIX/"
|
|
47
|
+
|
|
48
|
+
# Move each instance
|
|
49
|
+
for inst in "${INSTANCES[@]}"; do
|
|
50
|
+
REL="${inst#$ROOT/}"
|
|
51
|
+
PARENT_DIR=$(dirname "$REL")
|
|
52
|
+
ARCHIVE_PARENT="$ROOT/_archive/$PARENT_DIR"
|
|
53
|
+
mkdir -p "$ARCHIVE_PARENT"
|
|
54
|
+
mv "$inst" "$ARCHIVE_PARENT/$PROJECT-$SUFFIX"
|
|
55
|
+
echo " Moved: $REL/ → _archive/$PARENT_DIR/$PROJECT-$SUFFIX/"
|
|
56
|
+
done
|
|
57
|
+
|
|
58
|
+
# Write ARCHIVED.md
|
|
59
|
+
cat > "$ROOT/_archive/projects/$PROJECT-$SUFFIX/ARCHIVED.md" << EOF
|
|
60
|
+
---
|
|
61
|
+
archived_at: $TIMESTAMP
|
|
62
|
+
project: $PROJECT
|
|
63
|
+
archive_suffix: $SUFFIX
|
|
64
|
+
reason: ${REASON:-(not specified)}
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
# Archived: $PROJECT
|
|
68
|
+
|
|
69
|
+
## Paths archived
|
|
70
|
+
- _archive/projects/$PROJECT-$SUFFIX/ (project root)
|
|
71
|
+
$(for inst in "${INSTANCES[@]}"; do
|
|
72
|
+
REL="${inst#$ROOT/}"
|
|
73
|
+
PARENT_DIR=$(dirname "$REL")
|
|
74
|
+
echo "- _archive/$PARENT_DIR/$PROJECT-$SUFFIX/ (instance)"
|
|
75
|
+
done)
|
|
76
|
+
|
|
77
|
+
## To restore
|
|
78
|
+
\`\`\`bash
|
|
79
|
+
bash scripts/unarchive-project.sh $PROJECT $SUFFIX
|
|
80
|
+
\`\`\`
|
|
81
|
+
EOF
|
|
82
|
+
|
|
83
|
+
# Operation log
|
|
84
|
+
LOG_DIR="$ROOT/chief-of-staff/logs/$(date +%Y-%m)"
|
|
85
|
+
mkdir -p "$LOG_DIR"
|
|
86
|
+
LOG_FILE="$LOG_DIR/operations-$(date +%Y-%m-%d).md"
|
|
87
|
+
{
|
|
88
|
+
echo ""
|
|
89
|
+
echo "## $TIMESTAMP — archive-project: $PROJECT"
|
|
90
|
+
echo "Suffix: $SUFFIX"
|
|
91
|
+
echo "Instances archived: ${#INSTANCES[@]}"
|
|
92
|
+
[ -n "$REASON" ] && echo "Reason: $REASON"
|
|
93
|
+
} >> "$LOG_FILE"
|
|
94
|
+
|
|
95
|
+
echo ""
|
|
96
|
+
echo "✓ Archive complete."
|
|
97
|
+
echo " ARCHIVED.md: $ROOT/_archive/projects/$PROJECT-$SUFFIX/ARCHIVED.md"
|
|
98
|
+
echo " Operation log: $LOG_FILE"
|