@nanocollective/roster 0.1.0-alpha.1 → 0.1.0-alpha.11
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 +65 -84
- package/dist/cli.js +4687 -2495
- package/docs/README.md +19 -11
- package/docs/agents.md +328 -13
- package/docs/architecture.md +13 -5
- package/docs/charters/cmo.md +69 -0
- package/docs/charters/cto.md +71 -0
- package/docs/charters/support.md +60 -0
- package/docs/commands.md +90 -11
- package/docs/concepts.md +64 -12
- package/docs/cost.md +39 -3
- package/docs/developing.md +16 -21
- package/docs/doctor-codes.md +21 -6
- package/docs/export.md +2 -1
- package/docs/extending.md +13 -4
- package/docs/getting-started.md +118 -80
- package/docs/images/brain.jpg +0 -0
- package/docs/images/org.jpg +0 -0
- package/docs/images/prompt.jpg +0 -0
- package/docs/images/setup-org.jpg +0 -0
- package/docs/images/setup-plan.jpg +0 -0
- package/docs/images/staff.jpg +0 -0
- package/docs/manual-steps.md +94 -101
- package/docs/memory.md +29 -8
- package/docs/org-yaml.md +74 -11
- package/docs/portal.md +261 -47
- package/docs/prompts.md +71 -11
- package/docs/security.md +43 -7
- package/docs/session-workflow.md +51 -21
- package/docs/staff-yaml.md +16 -7
- package/docs/troubleshooting.md +23 -20
- package/docs/upgrading.md +6 -0
- package/docs/writing-a-charter.md +33 -17
- package/package.json +1 -1
- package/templates/brain/.github/workflows/%%STAFF%%-daily.yaml +7 -0
- package/templates/brain/.github/workflows/%%STAFF%%-mention.yaml +16 -4
- package/templates/brain/CHARTER.md +3 -3
- package/templates/brain/README.md +1 -0
- package/templates/brain/log/decisions.md +3 -0
- package/templates/brain/staff.yaml +0 -1
- package/templates/brain/strategy/ideas.md +7 -0
- package/templates/ops/.github/workflows/session.yaml +117 -40
- package/templates/ops/agents.mjs +127 -8
- package/templates/ops/compose.mjs +77 -7
- package/templates/ops/inflight.mjs +157 -0
- package/templates/ops/org/operating.md +21 -7
- package/templates/ops/org/voice.md +9 -0
- package/templates/ops/prompts/_identity.md +8 -1
- package/templates/ops/prompts/_inflight.md +14 -0
- package/templates/ops/prompts/_paths.md +2 -1
- package/templates/ops/prompts/daily.md +16 -7
- package/templates/ops/prompts/mention.md +18 -2
- package/templates/ops/run-record.mjs +144 -0
- package/templates/portal/css/base.css +238 -64
- package/templates/portal/css/brain.css +30 -20
- package/templates/portal/css/diff.css +15 -10
- package/templates/portal/css/graph.css +12 -7
- package/templates/portal/css/health.css +32 -11
- package/templates/portal/css/inbox.css +117 -14
- package/templates/portal/css/layout.css +92 -41
- package/templates/portal/css/markdown.css +38 -15
- package/templates/portal/css/runs.css +13 -0
- package/templates/portal/css/setup.css +52 -39
- package/templates/portal/index.html +24 -3
- package/templates/portal/js/api.js +65 -4
- package/templates/portal/js/app.js +112 -12
- package/templates/portal/js/dialog.js +94 -4
- package/templates/portal/js/dom.js +25 -0
- package/templates/portal/js/icons.js +8 -1
- package/templates/portal/js/lightbox.js +273 -0
- package/templates/portal/js/md.js +23 -6
- package/templates/portal/js/mention.js +264 -0
- package/templates/portal/js/refresh.js +136 -6
- package/templates/portal/js/state.js +55 -8
- package/templates/portal/js/views/app.js +23 -5
- package/templates/portal/js/views/checklist.js +20 -7
- package/templates/portal/js/views/credential.js +93 -0
- package/templates/portal/js/views/docs.js +94 -4
- package/templates/portal/js/views/files.js +58 -14
- package/templates/portal/js/views/graph.js +1 -1
- package/templates/portal/js/views/health.js +178 -37
- package/templates/portal/js/views/inbox.js +938 -98
- package/templates/portal/js/views/memory.js +16 -1
- package/templates/portal/js/views/org.js +161 -61
- package/templates/portal/js/views/paste.js +29 -0
- package/templates/portal/js/views/prompt.js +57 -66
- package/templates/portal/js/views/repos.js +12 -7
- package/templates/portal/js/views/runonce.js +94 -0
- package/templates/portal/js/views/runs.js +165 -0
- package/templates/portal/js/views/setup.js +302 -56
- package/templates/portal/js/views/staff.js +143 -22
- package/templates/portal/js/yaml.js +134 -0
- package/templates/brain/.github/workflows/%%STAFF%%-pr-mention.yaml +0 -50
- package/templates/ops/prompts/pr-mention.md +0 -57
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Charter — Acme's Head of Support
|
|
2
|
+
|
|
3
|
+
> **An example to adapt, not a template.** Acme is invented: a small company whose product is an
|
|
4
|
+
> open-source scheduling app, `acme/acme-web`, run by one founder, Sam. Replace every specific
|
|
5
|
+
> with your own. The shape is what has worked; the words have to be yours.
|
|
6
|
+
|
|
7
|
+
*Who I am and what only I do. The shared half lives in `roster-ops/org/`. This file is the
|
|
8
|
+
difference between me and the rest of the staff, and nothing else.*
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Who I am
|
|
13
|
+
|
|
14
|
+
Acme's Head of Support. I make sure nobody who asks for help is left waiting, and that what
|
|
15
|
+
people ask about reaches the staff who can fix the cause.
|
|
16
|
+
|
|
17
|
+
## The mission
|
|
18
|
+
|
|
19
|
+
**Every question answered, and every repeated question made unnecessary.** An answer fixes one
|
|
20
|
+
person's day; a fixed doc or a filed bug fixes it for everyone after them.
|
|
21
|
+
|
|
22
|
+
## How I work, that others here do not
|
|
23
|
+
|
|
24
|
+
- **Oldest first.** Every run starts with the support queue, the `question` issues on
|
|
25
|
+
`acme/acme-web`, oldest unanswered at the top. Nothing sits past two working days without a
|
|
26
|
+
reply, even if the reply is "not yet, here is why".
|
|
27
|
+
- **I draft replies; Sam sends them.** Each is a `reply` issue on my tracker with the exact text
|
|
28
|
+
and a link to the thread. He sends it or edits it.
|
|
29
|
+
- **Three of the same question is a bug.** I file it on the CTO's tracker, labelled
|
|
30
|
+
`from-support`, with the three links. One-off questions do not become issues.
|
|
31
|
+
- **Docs are mine to fix.** A wrong or missing answer in `acme-web/docs/` gets a PR from a branch.
|
|
32
|
+
- **Weekly, one line per theme** in `strategy/themes.md`: what people asked about, how often. The
|
|
33
|
+
CMO reads it for copy; the CTO for priorities.
|
|
34
|
+
|
|
35
|
+
## Decision rights
|
|
36
|
+
|
|
37
|
+
| I do freely | I file an issue, then carry on |
|
|
38
|
+
|---|---|
|
|
39
|
+
| Drafting replies, and labelling support issues | Sending anything to a customer: a `reply` issue |
|
|
40
|
+
| PRs to the docs | Refunds, credits, anything touching money |
|
|
41
|
+
| Filing bugs for the CTO, and themes for the CMO | Anything involving a customer's personal data |
|
|
42
|
+
| Closing my own issues when the thread is answered | Promising a fix or a date |
|
|
43
|
+
|
|
44
|
+
## Guardrails on top of the org's
|
|
45
|
+
|
|
46
|
+
1. **Never ask a customer for a password, a card number, or anything they would not post in
|
|
47
|
+
public.** Point them at the account page instead.
|
|
48
|
+
2. **Never promise.** "The team is looking at it" is true; "fixed next week" is a commitment only
|
|
49
|
+
Sam makes.
|
|
50
|
+
3. **Personal data stays out of my repo.** A theme is written without names or emails.
|
|
51
|
+
|
|
52
|
+
## Where the rest of it lives
|
|
53
|
+
|
|
54
|
+
| | |
|
|
55
|
+
|---|---|
|
|
56
|
+
| How I operate | `roster-ops/org/operating.md` |
|
|
57
|
+
| What matters this month | `roster-ops/org/priorities.md` |
|
|
58
|
+
| What people ask about | `strategy/themes.md` |
|
|
59
|
+
| What I know | `memory/INDEX.md` |
|
|
60
|
+
| What is outstanding | the pinned status issue |
|
package/docs/commands.md
CHANGED
|
@@ -6,8 +6,10 @@ sidebar_order: 8
|
|
|
6
6
|
|
|
7
7
|
# Commands
|
|
8
8
|
|
|
9
|
-
Every command prints a plan and changes nothing unless you pass
|
|
10
|
-
`prompt`, `export` and `
|
|
9
|
+
Every command that changes anything prints a plan and changes nothing unless you pass
|
|
10
|
+
`--apply`. `lint`, `prompt`, `export`, `brief`, `doctor` and `fix` never change anything.
|
|
11
|
+
`portal` is the exception: it is interactive, and each change there is a button you press after
|
|
12
|
+
seeing what it will do.
|
|
11
13
|
|
|
12
14
|
## `roster fix`
|
|
13
15
|
|
|
@@ -44,11 +46,15 @@ Stand up a new tenant: the ops repo, the org layer, and the recorded merge base.
|
|
|
44
46
|
--apply
|
|
45
47
|
```
|
|
46
48
|
|
|
49
|
+
With `--apply` it also sets the ops repo's Actions access to "accessible from repositories in
|
|
50
|
+
the organisation", which is what lets every brain call its workflow. If GitHub refuses (it needs
|
|
51
|
+
admin on the repo), it prints the reason and the settings page to click instead.
|
|
52
|
+
|
|
47
53
|
Will not write `org/business.md`. That is yours.
|
|
48
54
|
|
|
49
55
|
## `roster hire <handle>`
|
|
50
56
|
|
|
51
|
-
Scaffold a staff member: repo,
|
|
57
|
+
Scaffold a staff member: repo, two callers, manifest, memory index, charter stub, labels,
|
|
52
58
|
pinned status issue, and peer wiring in both directions.
|
|
53
59
|
|
|
54
60
|
```
|
|
@@ -58,13 +64,23 @@ pinned status issue, and peer wiring in both directions.
|
|
|
58
64
|
--model <id>
|
|
59
65
|
--timeout <n> daily ceiling, minutes
|
|
60
66
|
--mention-timeout <n>
|
|
61
|
-
--pr-timeout <n>
|
|
62
67
|
--secret-prefix <X> secrets become <X>_APP_ID and <X>_APP_PRIVATE_KEY
|
|
63
68
|
--app <slug> defaults to the pattern the peers use
|
|
64
69
|
--public-app <slug> the shared public identity
|
|
70
|
+
--no-review-gate leave the product repos' branch rules alone
|
|
65
71
|
--apply
|
|
66
72
|
```
|
|
67
73
|
|
|
74
|
+
With `--apply` it also:
|
|
75
|
+
|
|
76
|
+
- commits and pushes, as you, what it changed in repos that already exist: each peer's
|
|
77
|
+
`staff.yaml`, `org.yaml`, and the new `staff.yaml` once the status issue has a number. The
|
|
78
|
+
plan lists each commit first, and a push that fails is reported and left for you.
|
|
79
|
+
- adds the new brain to the agent credential's org secret, if there is one, so the credential is
|
|
80
|
+
never asked for again. See [`roster credential`](#roster-credential).
|
|
81
|
+
- adds a review-before-merge ruleset to each product repo that does not already require an
|
|
82
|
+
approving review. See [security](security.md#the-review-gate).
|
|
83
|
+
|
|
68
84
|
## `roster app <handle>`
|
|
69
85
|
|
|
70
86
|
Create the GitHub App and put its credentials in the brain repo's secrets.
|
|
@@ -73,9 +89,55 @@ Create the GitHub App and put its credentials in the brain repo's secrets.
|
|
|
73
89
|
--public create the shared public identity instead
|
|
74
90
|
--port <n> localhost port for the hand-off. Default 4310.
|
|
75
91
|
--no-open print the URL rather than opening a browser
|
|
92
|
+
--apply actually create it; without it, prints the App name, secrets and repos
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Cannot install the App: GitHub asks a person to confirm which repos it reaches. It prints a link
|
|
96
|
+
to the install page with the org and every repo the staff member needs already selected (its
|
|
97
|
+
brain, its peers' trackers, the product repos), so confirming is one click. The pre-selection uses
|
|
98
|
+
`suggested_target_id` and `repository_ids[]`, which GitHub's own links use but does not document;
|
|
99
|
+
when the ids cannot be read the link is the plain install page. See
|
|
100
|
+
[manual steps](manual-steps.md).
|
|
101
|
+
|
|
102
|
+
## `roster credential`
|
|
103
|
+
|
|
104
|
+
Store the coding agent's credential once for the org.
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
--repo-secrets a secret on each brain repo, even where an org secret would work
|
|
108
|
+
--apply read the credential and store it
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
By default it is one organisation secret, named after the agent's `token_env`, shared with every
|
|
112
|
+
brain repo; `roster hire` adds each new brain to it. It uses a secret on each brain instead, and
|
|
113
|
+
the plan says why, when an org secret would not arrive: on GitHub Free an org secret does not
|
|
114
|
+
reach a private repo, and only an org owner can set one. Setting an org secret also needs the
|
|
115
|
+
`admin:org` scope on your gh token (`gh auth refresh -h github.com -s admin:org`); if it is
|
|
116
|
+
refused, the credential goes on each repo and the output says so.
|
|
117
|
+
|
|
118
|
+
The value comes from standard input, or a prompt that does not echo, and goes to `gh` on its
|
|
119
|
+
standard input. It is never on a command line and never on disk.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
claude setup-token # Claude Code; see docs/agents.md for the others
|
|
123
|
+
roster credential --apply
|
|
76
124
|
```
|
|
77
125
|
|
|
78
|
-
|
|
126
|
+
## `roster run <handle>`
|
|
127
|
+
|
|
128
|
+
Start one daily run now and follow it to the end.
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
--no-wait start it and print the link, without following it
|
|
132
|
+
--apply start the run
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Runs `gh workflow run <handle>-daily.yaml`, finds the run it started, and polls it until it
|
|
136
|
+
finishes. It prints the outcome, the step it failed at if it did, and the log's link. A success
|
|
137
|
+
is what `roster doctor` counts as proof that the App, its grant, the secrets and the callers all
|
|
138
|
+
work, so its "unproven" warning goes away. It is a real run and spends what a scheduled one
|
|
139
|
+
would, which is why it needs `--apply`. The staff card and Health have the same as
|
|
140
|
+
**Run once now**.
|
|
79
141
|
|
|
80
142
|
## `roster retire <handle>`
|
|
81
143
|
|
|
@@ -125,7 +187,8 @@ Carry framework changes into the tenant. See [upgrading](upgrading.md).
|
|
|
125
187
|
|
|
126
188
|
## `roster lint [handle]`
|
|
127
189
|
|
|
128
|
-
Check memory against the grammar
|
|
190
|
+
Check memory against the grammar, and warn when a fact, the index or the decision log is over
|
|
191
|
+
its [budget](memory.md#budgets). See [memory](memory.md).
|
|
129
192
|
|
|
130
193
|
```
|
|
131
194
|
--quiet print only problems
|
|
@@ -144,8 +207,9 @@ amend <who> change what a staff member is told, with the whole prompt attach
|
|
|
144
207
|
```
|
|
145
208
|
|
|
146
209
|
```
|
|
147
|
-
--kind <k> for amend: daily | mention
|
|
210
|
+
--kind <k> for amend: daily | mention (default: daily)
|
|
148
211
|
--want <text> for amend: what you want changed
|
|
212
|
+
--example <e> for charter: cto, cmo, support or none (default: matched to the role)
|
|
149
213
|
--ops <dir>
|
|
150
214
|
```
|
|
151
215
|
|
|
@@ -156,6 +220,11 @@ roster brief charter cto | pbcopy
|
|
|
156
220
|
roster brief voice > /tmp/brief.md
|
|
157
221
|
```
|
|
158
222
|
|
|
223
|
+
`charter` carries one of the [worked examples](writing-a-charter.md#worked-examples) as a
|
|
224
|
+
model to adapt, matched to the role by handle or name. It is a model for the shape, not content
|
|
225
|
+
to copy, and the brief still interviews you first. `--example` picks another; `--example none`
|
|
226
|
+
leaves it out. The portal's copy-a-prompt has the same choice.
|
|
227
|
+
|
|
159
228
|
`amend` is the different one. It carries the composed prompt and every file it is assembled
|
|
160
229
|
from, so the agent you paste it into does not have to ask for any of them. The portal's Prompt
|
|
161
230
|
screen builds the same thing, and offers it per audit finding.
|
|
@@ -177,14 +246,19 @@ roster brief discover > roster-ops/.claude/commands/discover.md
|
|
|
177
246
|
Compose and print what a staff member is actually sent.
|
|
178
247
|
|
|
179
248
|
```
|
|
180
|
-
--kind daily|mention
|
|
249
|
+
--kind daily|mention
|
|
181
250
|
--diff <workflow.yaml>
|
|
251
|
+
--inflight
|
|
182
252
|
```
|
|
183
253
|
|
|
184
|
-
|
|
254
|
+
A run also carries the pull requests people have open on the product repos. `--inflight` reads
|
|
255
|
+
them through your own `gh` and includes them; without it that section is left out, so the output
|
|
256
|
+
does not move with somebody else's branch.
|
|
257
|
+
|
|
258
|
+
`mention` needs trigger context:
|
|
185
259
|
|
|
186
260
|
```bash
|
|
187
|
-
ROSTER_CONTEXT='{"issue_number":"1","comment_id":"1","
|
|
261
|
+
ROSTER_CONTEXT='{"issue_number":"1","comment_id":"1","repo":"o/r"}' \
|
|
188
262
|
roster prompt cto --kind mention
|
|
189
263
|
```
|
|
190
264
|
|
|
@@ -197,8 +271,12 @@ which is the shortest way in.
|
|
|
197
271
|
--port <n> default 4300
|
|
198
272
|
--host <a> default 127.0.0.1. Anything else exposes write actions to the network.
|
|
199
273
|
--dir <path> where a tenant would be created or checked out. Default: here.
|
|
274
|
+
--no-open don't open a browser
|
|
200
275
|
```
|
|
201
276
|
|
|
277
|
+
It opens the page in your browser when it starts. It stays closed in CI, over SSH, when output
|
|
278
|
+
is not a terminal, or with `BROWSER=none`.
|
|
279
|
+
|
|
202
280
|
**With no tenant where you started it, this is the setup screen**: it stands up a new org, or
|
|
203
281
|
checks out one that already runs roster. Local only. See [the portal](portal.md).
|
|
204
282
|
|
|
@@ -206,7 +284,8 @@ Views: Inbox, Org, Staff, Docs, and per staff member Brain, Prompt, Graph, What
|
|
|
206
284
|
|
|
207
285
|
It can act as you through your own `gh`: reply, close, reopen and open issues; hire and retire;
|
|
208
286
|
edit and commit the org layer, prompt fragments and charters; create a staff member's GitHub App;
|
|
209
|
-
|
|
287
|
+
store the agent credential; set the ops repo's Actions access; start one run and follow it; and
|
|
288
|
+
copy a prompt for authoring the two files nothing can generate.
|
|
210
289
|
|
|
211
290
|
## `roster export`
|
|
212
291
|
|
package/docs/concepts.md
CHANGED
|
@@ -6,23 +6,64 @@ sidebar_order: 3
|
|
|
6
6
|
|
|
7
7
|
# Concepts
|
|
8
8
|
|
|
9
|
+
## The six things you need to know
|
|
10
|
+
|
|
11
|
+
Enough to set up an org and read what it does. Everything after this section is detail you
|
|
12
|
+
can learn when you need it.
|
|
13
|
+
|
|
14
|
+
1. **The org layer.** One private repo, `<org>/roster-ops`, holds what every staff member
|
|
15
|
+
shares: what the business is (`org/business.md`), what matters this month
|
|
16
|
+
(`org/priorities.md`), the house voice and the guardrails. Change it once and every staff
|
|
17
|
+
member has it on their next run. [More](#the-ops-repo).
|
|
18
|
+
2. **A staff member is a repo.** Each one has a private repo, its *brain*: what it knows, what
|
|
19
|
+
it is working on, and what it has decided. There is no database and no server; the portal
|
|
20
|
+
reads the repos. [More](#the-brain).
|
|
21
|
+
3. **The charter.** `CHARTER.md` in the brain says who this staff member is and what it
|
|
22
|
+
decides alone. You write it, with a brief that interviews you; roster never generates one,
|
|
23
|
+
because a generated charter makes a generic agent. [More](#charter-and-manifest).
|
|
24
|
+
4. **Memory.** `memory/INDEX.md` is one line per fact, read at the start of every run. The
|
|
25
|
+
agent writes it and deletes from it; you can read and correct it in the portal. That is how
|
|
26
|
+
a staff member remembers yesterday. [More](memory.md).
|
|
27
|
+
5. **The daily run.** A scheduled GitHub Actions workflow in each brain wakes the staff member,
|
|
28
|
+
hands it a prompt built from the org layer plus its charter and memory, and it does one piece
|
|
29
|
+
of work and writes down what happened. [More](#kinds-of-run).
|
|
30
|
+
6. **Mentions.** Write `@handle` in an issue or comment on a staff member's own tracker and it
|
|
31
|
+
runs to answer that, between daily runs. Nothing on a product repo wakes anybody; you ask
|
|
32
|
+
them on their tracker. [More](#kinds-of-run).
|
|
33
|
+
|
|
34
|
+
Everything below, and the rest of the docs, is detail: identities, peers, surfaces, the
|
|
35
|
+
prompt's layers, upgrading. None of it is needed to get a first run.
|
|
36
|
+
|
|
9
37
|
## The ops repo
|
|
10
38
|
|
|
11
39
|
`<org>/roster-ops` holds two different kinds of thing, and the split matters.
|
|
12
40
|
|
|
13
|
-
**`org/` is yours.** `business.md`, `
|
|
14
|
-
business truth and the shared half of every staff member's
|
|
15
|
-
|
|
16
|
-
|
|
41
|
+
**`org/` is yours.** `business.md`, `priorities.md`, `voice.md`, `guardrails.md`,
|
|
42
|
+
`operating.md`. This is the business truth and the shared half of every staff member's
|
|
43
|
+
instructions. Edit it freely: the
|
|
44
|
+
[Org screen](portal.md#org) lists every one of these off disk with an Edit button, and saving
|
|
45
|
+
commits and pushes. A change here reaches everybody on their next run, which is the point: a
|
|
46
|
+
rule every staff member should follow is one edit, not one per repo.
|
|
17
47
|
|
|
18
48
|
**Everything else is machinery** and belongs to the framework: `compose.mjs`, `agents.mjs`,
|
|
19
|
-
`runner-plan.mjs`, `.github/workflows/session.yaml`. Editing these works right up until the
|
|
49
|
+
`runner-plan.mjs`, `inflight.mjs`, `run-record.mjs`, `.github/workflows/session.yaml`. Editing these works right up until the
|
|
20
50
|
framework changes the same file, at which point your change is a conflict at best and silently
|
|
21
51
|
reverted at worst. Fix machinery in the framework, then `roster upgrade`.
|
|
22
52
|
|
|
23
53
|
`roster upgrade` enforces this distinction. It reports an edit to a framework-owned file even
|
|
24
54
|
when nothing has collided yet, because "not broken yet" is the state a lost fix sits in.
|
|
25
55
|
|
|
56
|
+
## Priorities
|
|
57
|
+
|
|
58
|
+
`org/priorities.md` is the one direction every staff member shares: what matters this month,
|
|
59
|
+
ranked, and what is out of scope. It is composed into every daily run, a run picks work that
|
|
60
|
+
serves it, and a PR names the priority it serves. Keep it to three priorities or fewer, and
|
|
61
|
+
rewrite it when the month turns.
|
|
62
|
+
|
|
63
|
+
Without it each staff member picks its own work from its own charter, and they drift. `roster
|
|
64
|
+
init` writes a stub; `roster doctor` warns while it is missing or still the stub. An org that
|
|
65
|
+
predates it just adds the file.
|
|
66
|
+
|
|
26
67
|
## The brain
|
|
27
68
|
|
|
28
69
|
A staff member's repository *is* their memory. There is no database.
|
|
@@ -34,12 +75,12 @@ A staff member's repository *is* their memory. There is no database.
|
|
|
34
75
|
| `memory/INDEX.md` | one line per fact, read in full at every boot |
|
|
35
76
|
| `memory/notes/` | the argument behind a fact, read only when that fact is in play |
|
|
36
77
|
| `log/decisions.md` | why things were decided. Not boot context. |
|
|
37
|
-
| `.github/workflows/` |
|
|
78
|
+
| `.github/workflows/` | two callers, about forty lines each |
|
|
38
79
|
|
|
39
80
|
## Charter and manifest
|
|
40
81
|
|
|
41
82
|
Two halves of one thing. The charter is prose for the agent; the manifest is fields for the
|
|
42
|
-
machinery. `roster lint
|
|
83
|
+
machinery. [Health](portal.md#health), and `roster lint`, fail if they disagree.
|
|
43
84
|
|
|
44
85
|
The charter is the only file roster refuses to generate. A generated charter produces a generic
|
|
45
86
|
agent, and a generic agent produces work that is plausible, competent-looking and about nothing
|
|
@@ -64,10 +105,12 @@ exports declares `gallery` and `table`; nothing in the portal knows what a CMO i
|
|
|
64
105
|
|
|
65
106
|
```
|
|
66
107
|
org/operating.md + org/guardrails.md + org/voice.md + org/business.md
|
|
67
|
-
+ <staff>/CHARTER.md + prompts/<kind>.md
|
|
108
|
+
+ org/priorities.md + <staff>/CHARTER.md + prompts/<kind>.md
|
|
68
109
|
```
|
|
69
110
|
|
|
70
|
-
Built at run time by `compose.mjs` in the tenant's own repo. See it for yourself
|
|
111
|
+
Built at run time by `compose.mjs` in the tenant's own repo. See it for yourself on the
|
|
112
|
+
[Prompt screen](portal.md#prompt), which shows the composed text and every layer that went into
|
|
113
|
+
it, or from a terminal:
|
|
71
114
|
|
|
72
115
|
```bash
|
|
73
116
|
roster prompt cto --kind daily
|
|
@@ -83,10 +126,19 @@ control.
|
|
|
83
126
|
|---|---|
|
|
84
127
|
| `daily` | the scheduled session. Boot, work, hand off. |
|
|
85
128
|
| `mention` | `@handle` in a comment or a new issue body. A task, not a session. |
|
|
86
|
-
| `pr-mention` | a review comment on the public product repo, forwarded in. |
|
|
87
129
|
|
|
88
|
-
|
|
89
|
-
|
|
130
|
+
A `mention` prompt refuses to compose without trigger context, because it is written for the
|
|
131
|
+
comment that woke it. That is correct behaviour, not a bug.
|
|
132
|
+
|
|
133
|
+
**Nothing in a product repo wakes anybody.** A pull request is on the product repo, and a staff member's caller workflow is in their own brain repo and
|
|
134
|
+
gates on their `@handle` appearing *there*. So naming somebody in a reply where a comment will
|
|
135
|
+
not reach them offers, under the box, to open the request on their tracker as well. One press
|
|
136
|
+
posts your words on the thread and sends them the pull request, the branch, the hunk you were
|
|
137
|
+
looking at if you started from a file, and an instruction to answer on the pull request rather
|
|
138
|
+
than in the tracker it arrived in.
|
|
139
|
+
|
|
140
|
+
It is two `gh` calls as you, rather than a workflow in the product repo with its own gate and
|
|
141
|
+
its own credential. See [the portal](portal.md#asking-for-a-change).
|
|
90
142
|
|
|
91
143
|
## Identities
|
|
92
144
|
|
package/docs/cost.md
CHANGED
|
@@ -12,17 +12,53 @@ Three separate bills, and they behave differently.
|
|
|
12
12
|
|
|
13
13
|
The largest by far, and the one that scales with how much work you ask for.
|
|
14
14
|
|
|
15
|
+
On a Claude subscription, through a Claude Code OAuth token, it is a flat subscription rather
|
|
16
|
+
than spend per token, and what grows with a session is how much of its usage you take. That is
|
|
17
|
+
how Pip's staff run.
|
|
18
|
+
|
|
15
19
|
A session's cost is roughly its length. Ours run 11 to 55 minutes of wall clock, and a longer
|
|
16
20
|
session is a bigger bill as well as a slower one. The lever that matters is not the model
|
|
17
21
|
setting, it is how much you ask a staff member to do each morning and how much context it has
|
|
18
22
|
to read to start.
|
|
19
23
|
|
|
20
24
|
That is why the memory system is shaped the way it is. Boot context here went from about 52,000
|
|
21
|
-
words to about
|
|
25
|
+
words to about 10,000 today by moving from a narrative status file to one line per fact. That is a
|
|
22
26
|
direct, repeated saving on every run of every staff member.
|
|
23
27
|
|
|
24
28
|
**Watch for sessions growing into their ceiling.** A run that gets killed at
|
|
25
|
-
`timeout_minutes` has been paid for and produced nothing. `roster doctor
|
|
29
|
+
`timeout_minutes` has been paid for and produced nothing. Health, and `roster doctor`, report
|
|
30
|
+
the ratio.
|
|
31
|
+
|
|
32
|
+
## What each run cost
|
|
33
|
+
|
|
34
|
+
Every session writes down what it was, after the agent finishes or fails: staff, kind, outcome,
|
|
35
|
+
duration, and turns, cost and tokens where the agent reports them. It goes in the job summary,
|
|
36
|
+
and into an artifact called `roster-run` holding one `run.json`.
|
|
37
|
+
|
|
38
|
+
Which agents report what:
|
|
39
|
+
|
|
40
|
+
| Agent | Turns, cost, tokens |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `claude-code-action` | yes, from the Action's execution file |
|
|
43
|
+
| `claude` | yes, from `--output-format json` |
|
|
44
|
+
| anything else | only if its `run` writes the agent's result JSON to `$AGENT_RESULT_FILE` |
|
|
45
|
+
|
|
46
|
+
What is not reported is recorded as unknown, never as zero. A total built from guesses is worse
|
|
47
|
+
than none, so every total says how many runs it could price. The cost is the agent's own figure:
|
|
48
|
+
on a subscription it is what the tokens would have cost, not what you were billed.
|
|
49
|
+
|
|
50
|
+
The portal's [Runs](portal.md#runs) screen lists them per staff member, with a link to each log
|
|
51
|
+
and a 30-day total.
|
|
52
|
+
|
|
53
|
+
## Budgets
|
|
54
|
+
|
|
55
|
+
An optional [`budget`](org-yaml.md#budget) in `org.yaml`, in dollars over any trailing 30 days,
|
|
56
|
+
for the org or for one staff member. Past it, `roster doctor` warns (`budget`) and the Runs
|
|
57
|
+
screen marks the total.
|
|
58
|
+
|
|
59
|
+
It is a warning and never a cap. Stopping a session mid-run fails it after the work is done and
|
|
60
|
+
committed, which is also why there is no `--max-turns`. Use the warning to go and
|
|
61
|
+
look at which runs cost most and why; the levers are below.
|
|
26
62
|
|
|
27
63
|
## GitHub Actions minutes
|
|
28
64
|
|
|
@@ -57,5 +93,5 @@ on your machine when you ask it to, and the machinery is vendored into the tenan
|
|
|
57
93
|
being raised is a session that has stopped fitting its job.
|
|
58
94
|
- **Give a mention workflow a shorter ceiling than a daily one.** A focused task that runs for
|
|
59
95
|
an hour has gone wrong, and the ceiling is the only thing that stops it.
|
|
60
|
-
- **Check the ratio, not the last run.**
|
|
96
|
+
- **Check the ratio, not the last run.** Health reports how many of the last ten runs
|
|
61
97
|
succeeded. One bad run is noise; four is a bill.
|
package/docs/developing.md
CHANGED
|
@@ -34,10 +34,8 @@ test/ one file per area
|
|
|
34
34
|
module per screen under `js/views/`. `roster portal` serves them from `/assets`, reading each
|
|
35
35
|
file per request. Editing a stylesheet and reloading the page is the whole edit loop.
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
the module graph itself, and a bundler would have been a build step in a tool whose selling
|
|
40
|
-
point is that it does not have one.
|
|
37
|
+
No bundler, because the browser resolves the module graph itself, and a bundler would be a
|
|
38
|
+
build step in a tool whose selling point is that it does not have one.
|
|
41
39
|
|
|
42
40
|
```
|
|
43
41
|
templates/portal/
|
|
@@ -64,13 +62,12 @@ registers into at boot.
|
|
|
64
62
|
|
|
65
63
|
## The rule that matters
|
|
66
64
|
|
|
67
|
-
**Never fix a generated file in a tenant.** `compose.mjs`, `agents.mjs`, `runner-plan.mjs
|
|
68
|
-
`session.yaml` live in `templates/ops/`. Fix them there and run `roster upgrade`.
|
|
65
|
+
**Never fix a generated file in a tenant.** `compose.mjs`, `agents.mjs`, `runner-plan.mjs`,
|
|
66
|
+
`inflight.mjs`, `run-record.mjs` and `session.yaml` live in `templates/ops/`. Fix them there and run `roster upgrade`.
|
|
69
67
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
collided, and `roster upgrade --check` fails on it.
|
|
68
|
+
A fix made in the tenant's copy goes unnoticed until the framework next touches that file, and
|
|
69
|
+
then it is a conflict. So `roster upgrade` reports an edit to a framework-owned file whether or
|
|
70
|
+
not anything has collided, and `roster upgrade --check` fails on it.
|
|
74
71
|
|
|
75
72
|
## Template classes
|
|
76
73
|
|
|
@@ -101,21 +98,19 @@ marker, or the leftover line is stranded.
|
|
|
101
98
|
|
|
102
99
|
## How the tests are meant to work
|
|
103
100
|
|
|
104
|
-
Three habits, each of which
|
|
101
|
+
Three habits, each of which guards against a test that passes without testing anything.
|
|
105
102
|
|
|
106
|
-
**Test the harness, not just the code.** The portal
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
real modules under a DOM shim and there is nothing to get wrong.
|
|
103
|
+
**Test the harness, not just the code.** The portal's state is an exported object, so the tests
|
|
104
|
+
import the real modules under a DOM shim and drive the same state the page does. A test that
|
|
105
|
+
sets a property on something the code never reads cannot fail.
|
|
110
106
|
|
|
111
|
-
**Run it against reality.** The
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
107
|
+
**Run it against reality when you can.** The suite builds a temporary tenant by default, so it
|
|
108
|
+
runs for anybody who clones the repo. Set `ROSTER_TEST_WORKSPACE=<dir>` to run the portal and
|
|
109
|
+
doctor tests against a real workspace instead, which is how you catch real data growing a shape
|
|
110
|
+
the code cannot handle: templated filenames, for instance, that a comparison forgot to render.
|
|
115
111
|
|
|
116
112
|
**Mutation-test the invariants.** For anything asserting "this behaviour must not regress",
|
|
117
|
-
break it deliberately and check the test fails.
|
|
118
|
-
way, one mutation each.
|
|
113
|
+
break it deliberately and check the test fails. If it does not, the assertion is decoration.
|
|
119
114
|
|
|
120
115
|
## Adding a command
|
|
121
116
|
|
package/docs/doctor-codes.md
CHANGED
|
@@ -6,6 +6,9 @@ sidebar_order: 19
|
|
|
6
6
|
|
|
7
7
|
# doctor codes
|
|
8
8
|
|
|
9
|
+
The portal's [Health](portal.md#health) screen shows these same findings, each with its fix, and
|
|
10
|
+
turns the ones an agent could fix into a single brief. This page is the reference behind both.
|
|
11
|
+
|
|
9
12
|
Every finding `roster doctor` can emit. Each carries a stable `id`, which is what
|
|
10
13
|
`--json` reports and what to quote in an issue.
|
|
11
14
|
|
|
@@ -22,12 +25,21 @@ ran at all.
|
|
|
22
25
|
|---|---|
|
|
23
26
|
| `gh` | Whether `gh` is installed and authenticated. A warning here means every network check was skipped, not that anything is wrong. |
|
|
24
27
|
| `org.yaml` | The org manifest parsed, and how much it declares. |
|
|
25
|
-
| `human` | **fail.** `org.yaml`
|
|
28
|
+
| `human` | **fail.** `org.yaml` names nobody with a `github` login, in either `human` or `humans`. The mention callers gate on those logins, so nothing can wake an agent. |
|
|
29
|
+
| `human.login` | One of the people in `humans` has a name but no `github` login. They read as somebody the staff answer to and are not: the gate can never match them. |
|
|
26
30
|
| `repo` | Every repo in `org.yaml` is reachable. A failure means it does not exist or your `gh` cannot see it. |
|
|
27
31
|
| `repo.visibility` | A repo's real visibility disagrees with what `org.yaml` records. Cosmetic, but the posture it records is then fiction. |
|
|
32
|
+
| `agent` | Which runner this org uses, resolved from the tenant's own `agents.mjs`. **fail** if `org.yaml` names one it does not know. |
|
|
33
|
+
| `agent.config` | **fail.** The agent needs a config file of its own and it is missing, or still has a `FILL IN` in it. Nanocoder is the one preset that does: it is a client rather than a model, so without a provider it starts, finds nothing to call, and exits. |
|
|
28
34
|
| `business` | **fail** if `org/business.md` is missing. Every prompt is composed on top of it. |
|
|
29
35
|
| `business.stub` | `org/business.md` is still the questions it shipped with. Nothing errors; the agents just write competent work about a business that does not exist. |
|
|
30
|
-
| `
|
|
36
|
+
| `priorities` | No `org/priorities.md`. Nothing breaks; each staff member just picks its own direction. See [concepts](concepts.md#priorities). |
|
|
37
|
+
| `priorities.stub` | `org/priorities.md` is still the stub `roster init` wrote. |
|
|
38
|
+
| `actions-access` | **fail** unless the ops repo is callable from the whole organisation. This is the "workflow not found" trap. See [manual steps](manual-steps.md#what-roster-does-for-you). |
|
|
39
|
+
| `workflows` | No workflow in the repo is failing run after run. Reported for the ops repo here, and for each brain repo under its staff member. |
|
|
40
|
+
| `workflows.failing` | **fail.** A workflow that is not one of roster's callers has failed at least its last two runs, with the date it started. Skipped and cancelled runs are stepped over. This is the canary that goes red and stays red, because whatever would have said so broke with it. |
|
|
41
|
+
| `budget` | Trailing 30-day spend against a `budget` in `org.yaml`, for the org here and for a staff member under their name. A warning when it is past, never a failure, and only read when a budget is set. Cost comes from each run's record, so it says how many runs it could price. See [cost](cost.md#budgets). |
|
|
42
|
+
| `review-gate` | One per product repo. **fail** when nothing requires a pull request on its default branch, or a staff App can bypass the rule; a warning when a PR is required with no approving review, or the settings cannot be read. See [security](security.md#the-review-gate). |
|
|
31
43
|
| `upgrade` | The tenant is in sync with the framework. |
|
|
32
44
|
| `upgrade.stale` | Generated files are behind. `roster upgrade --apply`. |
|
|
33
45
|
| `upgrade.owned` | **fail.** A framework-owned file was edited in the tenant. Move the change upstream or the next upgrade reverts it. |
|
|
@@ -49,12 +61,12 @@ ran at all.
|
|
|
49
61
|
| `callers.uses` | **fail.** A caller references no reusable workflow, or one in a different organisation. A private reusable workflow is only callable inside its own org. |
|
|
50
62
|
| `callers.target` | **fail.** A caller points at a workflow file that is not in the ops repo. Fails at run time as "workflow not found". |
|
|
51
63
|
| `surfaces` | A surface declared in `staff.yaml` is not on disk. The portal renders nothing for it. |
|
|
52
|
-
| `secrets` | Every secret the callers reference exists on the brain repo. Derived from the callers themselves, not a fixed list. |
|
|
64
|
+
| `secrets` | Every secret the callers reference exists on the brain repo, or is an organisation secret shared with it. Derived from the callers themselves, not a fixed list. |
|
|
53
65
|
| `labels` | Every label declared in `staff.yaml` exists. An agent applying a label that does not exist gets an API error mid-run. |
|
|
54
66
|
| `peer-labels` | The `from-<handle>` label exists on the *peer's* tracker, which is where this staff member's asks land. |
|
|
55
67
|
| `status-issue` | The declared status issue is actually pinned. If not, the place you look is not the place the agent maintains. |
|
|
56
68
|
| `runs` | A window of recent runs. See below. |
|
|
57
|
-
| `runs.timeout` | **fail.** Runs were killed at a ceiling. |
|
|
69
|
+
| `runs.timeout` | **fail.** Runs were killed at a ceiling. Drops to `ok` once the ceiling has been raised *and* a run has finished since the last kill: the fix is made and proved, and the old runs are history rather than a problem. |
|
|
58
70
|
| `runs.cancelled` | Runs were cancelled short of any ceiling, with their durations. |
|
|
59
71
|
|
|
60
72
|
## Reading `runs`
|
|
@@ -63,8 +75,11 @@ This is the only check that proves the whole chain works, so it is worth underst
|
|
|
63
75
|
|
|
64
76
|
- **"has never run"** is a warning, not an `ok`. Nothing has exercised the App grant or the
|
|
65
77
|
secrets, so nothing is known.
|
|
66
|
-
- **"all gated out
|
|
67
|
-
normal
|
|
78
|
+
- **"all gated out"** means every recent trigger was `skipped`, which is a mention workflow's
|
|
79
|
+
normal state: every comment on the tracker fires it and the gate drops all but the real ones.
|
|
80
|
+
It is only a warning when *nothing* in that repo has finished a run, because the App grant
|
|
81
|
+
belongs to the repository rather than to the workflow, so one finished run proves it for all
|
|
82
|
+
of them.
|
|
68
83
|
- **"ran to a Nm ceiling and were killed"** is a timeout. GitHub reports those as `cancelled`,
|
|
69
84
|
so doctor identifies them by duration. If the ceiling it names differs from the one the
|
|
70
85
|
caller sets today, it says so: those runs happened under the old setting.
|
package/docs/export.md
CHANGED
|
@@ -22,7 +22,8 @@ that reads it gets the same view without reimplementing the memory grammar.
|
|
|
22
22
|
| `org` | the GitHub organisation |
|
|
23
23
|
| `name` | the business name |
|
|
24
24
|
| `opsName` | the ops repo's directory, so a consumer can address `org.yaml` and `org/*.md` by path |
|
|
25
|
-
| `human` | the
|
|
25
|
+
| `human` | the first human, normalised: `{ github, name, marker, role }`. Kept for consumers written when an org had exactly one |
|
|
26
|
+
| `humans[]` | everyone the staff answer to, in order, read from `humans` or the singular `human`. `human` is `humans[0]` |
|
|
26
27
|
| `generatedAt` | ISO timestamp |
|
|
27
28
|
| `staff[]` | one entry per staff member |
|
|
28
29
|
|
package/docs/extending.md
CHANGED
|
@@ -12,6 +12,11 @@ Four seams, in the order you are likely to reach for them.
|
|
|
12
12
|
|
|
13
13
|
Edit `org/*.md` in the ops repo. It reaches every staff member on their next run.
|
|
14
14
|
|
|
15
|
+
The [Org screen](portal.md#org) is exactly this seam: every one of these files listed off disk
|
|
16
|
+
with a line saying what it is for, an Edit button, and a save that commits and pushes. The list
|
|
17
|
+
comes off disk rather than being written into the page, so a file you add yourself is editable
|
|
18
|
+
there too.
|
|
19
|
+
|
|
15
20
|
| File | For |
|
|
16
21
|
|---|---|
|
|
17
22
|
| `business.md` | what the business is. The one everything else is downstream of. |
|
|
@@ -19,8 +24,8 @@ Edit `org/*.md` in the ops repo. It reaches every staff member on their next run
|
|
|
19
24
|
| `guardrails.md` | non-negotiables. What nobody may do, regardless of charter. |
|
|
20
25
|
| `operating.md` | the autonomy contract: the boot ritual, the hand-off, decision rights. |
|
|
21
26
|
|
|
22
|
-
This is the seam that pays. A
|
|
23
|
-
|
|
27
|
+
This is the seam that pays. A rule written here is one file, and the next morning everybody
|
|
28
|
+
has it.
|
|
24
29
|
|
|
25
30
|
Keep the split honest. If a rule would be true of every staff member you will ever hire, it
|
|
26
31
|
belongs here. If it is about one role, it belongs in that role's charter.
|
|
@@ -34,7 +39,6 @@ _identity.md who you are posting as, and where
|
|
|
34
39
|
_paths.md where things are in the runner checkout
|
|
35
40
|
daily.md the scheduled session
|
|
36
41
|
mention.md a focused task from a comment
|
|
37
|
-
pr-mention.md a review comment forwarded from the product repo
|
|
38
42
|
```
|
|
39
43
|
|
|
40
44
|
The syntax is small on purpose: `{{ path.to.value }}`, `{{> partial.md }}`,
|
|
@@ -54,7 +58,12 @@ A staff member can override a fragment for themselves. `{{>? staff:prompts/work.
|
|
|
54
58
|
`daily.md` renders `prompts/work.md` from their own brain repo if it exists, and nothing if it
|
|
55
59
|
does not. That is how one role gets a different working ritual without changing anybody else's.
|
|
56
60
|
|
|
57
|
-
See what you actually built
|
|
61
|
+
See what you actually built on the [Prompt screen](portal.md#prompt), which walks the includes
|
|
62
|
+
rather than listing them from memory, so a fragment you just added shows up on it, marked with
|
|
63
|
+
the repo it came from. An optional fragment a role does not have is shown as absent rather than
|
|
64
|
+
hidden. The layers are editable there too, subject to the writable list on that page.
|
|
65
|
+
|
|
66
|
+
From a terminal:
|
|
58
67
|
|
|
59
68
|
```bash
|
|
60
69
|
roster prompt cto --kind daily
|