@nanocollective/roster 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +129 -0
- package/dist/cli.js +5679 -0
- package/docs/README.md +99 -0
- package/docs/agents.md +163 -0
- package/docs/architecture.md +121 -0
- package/docs/commands.md +223 -0
- package/docs/concepts.md +112 -0
- package/docs/cost.md +61 -0
- package/docs/developing.md +147 -0
- package/docs/doctor-codes.md +74 -0
- package/docs/export.md +113 -0
- package/docs/extending.md +97 -0
- package/docs/getting-started.md +134 -0
- package/docs/hosting.md +72 -0
- package/docs/manual-steps.md +163 -0
- package/docs/memory.md +71 -0
- package/docs/org-yaml.md +143 -0
- package/docs/portal.md +342 -0
- package/docs/prompts.md +133 -0
- package/docs/security.md +122 -0
- package/docs/session-workflow.md +112 -0
- package/docs/staff-yaml.md +163 -0
- package/docs/troubleshooting.md +189 -0
- package/docs/upgrading.md +83 -0
- package/docs/writing-a-charter.md +83 -0
- package/package.json +60 -0
- package/templates/brain/.github/workflows/%%STAFF%%-daily.yaml +33 -0
- package/templates/brain/.github/workflows/%%STAFF%%-mention.yaml +65 -0
- package/templates/brain/.github/workflows/%%STAFF%%-pr-mention.yaml +50 -0
- package/templates/brain/CHARTER.md +49 -0
- package/templates/brain/README.md +18 -0
- package/templates/brain/drafts/README.md +7 -0
- package/templates/brain/log/decisions.md +6 -0
- package/templates/brain/memory/INDEX.md +28 -0
- package/templates/brain/staff.yaml +44 -0
- package/templates/brain/strategy/README.md +7 -0
- package/templates/briefs/amend.md +60 -0
- package/templates/briefs/charter.md +47 -0
- package/templates/briefs/discover.md +61 -0
- package/templates/briefs/voice.md +53 -0
- package/templates/ops/.github/workflows/session.yaml +333 -0
- package/templates/ops/agents.mjs +143 -0
- package/templates/ops/compose.mjs +333 -0
- package/templates/ops/org/guardrails.md +14 -0
- package/templates/ops/org/operating.md +82 -0
- package/templates/ops/org/voice.md +40 -0
- package/templates/ops/prompts/_identity.md +14 -0
- package/templates/ops/prompts/_paths.md +15 -0
- package/templates/ops/prompts/daily.md +82 -0
- package/templates/ops/prompts/mention.md +53 -0
- package/templates/ops/prompts/pr-mention.md +57 -0
- package/templates/ops/runner-plan.mjs +65 -0
- package/templates/portal/css/base.css +104 -0
- package/templates/portal/css/brain.css +106 -0
- package/templates/portal/css/diff.css +28 -0
- package/templates/portal/css/graph.css +34 -0
- package/templates/portal/css/health.css +41 -0
- package/templates/portal/css/inbox.css +79 -0
- package/templates/portal/css/layout.css +98 -0
- package/templates/portal/css/markdown.css +54 -0
- package/templates/portal/css/setup.css +106 -0
- package/templates/portal/index.html +55 -0
- package/templates/portal/js/api.js +74 -0
- package/templates/portal/js/app.js +282 -0
- package/templates/portal/js/dialog.js +70 -0
- package/templates/portal/js/dom.js +106 -0
- package/templates/portal/js/icons.js +94 -0
- package/templates/portal/js/md.js +386 -0
- package/templates/portal/js/refresh.js +59 -0
- package/templates/portal/js/router.js +20 -0
- package/templates/portal/js/state.js +160 -0
- package/templates/portal/js/textdiff.js +96 -0
- package/templates/portal/js/views/app.js +128 -0
- package/templates/portal/js/views/brain.js +260 -0
- package/templates/portal/js/views/changed.js +157 -0
- package/templates/portal/js/views/checklist.js +87 -0
- package/templates/portal/js/views/docs.js +84 -0
- package/templates/portal/js/views/files.js +95 -0
- package/templates/portal/js/views/graph.js +436 -0
- package/templates/portal/js/views/health.js +158 -0
- package/templates/portal/js/views/inbox.js +549 -0
- package/templates/portal/js/views/memory.js +135 -0
- package/templates/portal/js/views/org.js +175 -0
- package/templates/portal/js/views/paste.js +142 -0
- package/templates/portal/js/views/prompt.js +412 -0
- package/templates/portal/js/views/repos.js +92 -0
- package/templates/portal/js/views/setup.js +344 -0
- package/templates/portal/js/views/staff.js +290 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Getting started"
|
|
3
|
+
description: "Stand up an org and a first staff member, in seven steps."
|
|
4
|
+
sidebar_order: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Getting started
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx @nanocollective/roster
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Run that in an empty directory. It opens a portal in your browser and walks the whole setup:
|
|
14
|
+
it checks `gh`, lists the organisations you can see, and asks which one.
|
|
15
|
+
|
|
16
|
+
**Two answers, and it works out which you need.** An organisation that does not run roster yet
|
|
17
|
+
gets one stood up. One that already does gets checked out here instead, ops repo and every
|
|
18
|
+
staff repo side by side, which is the shape the CI runner uses. That is how a second person on
|
|
19
|
+
a team joins an org somebody else set up.
|
|
20
|
+
|
|
21
|
+
From there the page carries the rest: the Actions setting that has to be clicked, the repos
|
|
22
|
+
your staff work in, hiring, each GitHub App, and a prompt you paste into your own AI to write
|
|
23
|
+
`org/business.md` and the charters.
|
|
24
|
+
|
|
25
|
+
You need `gh` authenticated, and a credential for whichever [coding agent](agents.md) you want
|
|
26
|
+
to run.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
The rest of this page is the same setup from a terminal. Everything the portal does, these do;
|
|
31
|
+
nothing writes without `--apply`.
|
|
32
|
+
|
|
33
|
+
## 1. Stand up the org
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
roster init --org acme --name "Acme Robotics"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
That prints the plan. Read it, then:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
roster init --org acme --name "Acme Robotics" --apply
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
You now have `acme/roster-ops`: the org layer, the runner machinery, and a recorded merge base
|
|
46
|
+
so later upgrades are merges rather than copies.
|
|
47
|
+
|
|
48
|
+
Then do the one thing that cannot wait: **Settings -> Actions -> General on `roster-ops`, set
|
|
49
|
+
access to "accessible from repositories in the organisation".** Skip it and every workflow
|
|
50
|
+
later fails with "workflow not found", which reads like a typo and is not one.
|
|
51
|
+
|
|
52
|
+
## 2. Say what the business is
|
|
53
|
+
|
|
54
|
+
Open `roster-ops/org/business.md`. It ships as questions. Answer them, or:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
roster brief discover # paste into whatever agent you use
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or, in Claude Code, `cd roster-ops && claude` then `/discover`. Both print the same brief:
|
|
61
|
+
`roster init` generates the slash command from it.
|
|
62
|
+
|
|
63
|
+
Do this before hiring anyone. It is composed into the top of every prompt, and an agent that
|
|
64
|
+
cannot answer these questions writes plausible work about a business that does not exist.
|
|
65
|
+
|
|
66
|
+
## 3. Hire someone
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
roster hire cto --name "Chief Technology Officer" --dir technology
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Read the plan. It lists every file, every label, the peer wiring in both directions, and the
|
|
73
|
+
things it cannot do for you. Then `--apply`.
|
|
74
|
+
|
|
75
|
+
For the first hire in a new org there is nobody to copy an identity from, so name them:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
roster hire cto --name "Chief Technology Officer" --dir technology \
|
|
79
|
+
--app acme-cto --public-app acme-robot --apply
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Later hires infer both from whoever is already there.
|
|
83
|
+
|
|
84
|
+
## 4. Give them an identity
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
roster app cto
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
A browser opens, GitHub asks you to confirm, and the App's id and private key go straight into
|
|
91
|
+
the repository's secrets. The key never touches disk.
|
|
92
|
+
|
|
93
|
+
Then **install it**, using the URL that command prints, granting it every tracker the staff
|
|
94
|
+
member writes to. This is the step that most often looks done and is not. See
|
|
95
|
+
[manual steps](manual-steps.md#3-install-the-app-and-grant-it-the-right-repositories).
|
|
96
|
+
|
|
97
|
+
## 5. Write the charter
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
roster brief charter cto # paste into whatever agent you use
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Or, in Claude Code, `cd technology && claude` then `/charter`. Same brief either way.
|
|
104
|
+
|
|
105
|
+
This is the file that decides everything else. [Writing a charter](writing-a-charter.md).
|
|
106
|
+
|
|
107
|
+
## 6. Check, then run one by hand
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
roster doctor cto
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Fix what it says. Then trigger the daily workflow once from the Actions tab and read the log.
|
|
114
|
+
|
|
115
|
+
**A workflow that has never run has proved nothing.** Not that the App is installed, not that
|
|
116
|
+
the grant took, not that the secrets are right. `doctor` says `unproven` rather than `fine` for
|
|
117
|
+
exactly this reason.
|
|
118
|
+
|
|
119
|
+
## 7. Look at it
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
roster portal
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Everything open across the org, every staff member's memory, what changed since yesterday, and
|
|
126
|
+
whether anything is unhealthy. Reads the repositories on disk, so keep them checked out
|
|
127
|
+
alongside each other.
|
|
128
|
+
|
|
129
|
+
## Where things go from here
|
|
130
|
+
|
|
131
|
+
- A second staff member: `roster hire`, then `roster app`. Peer wiring happens both ways.
|
|
132
|
+
- A change to how everyone writes: edit `org/voice.md` once. It reaches everybody on their next
|
|
133
|
+
run.
|
|
134
|
+
- A framework update: `roster upgrade`. See [upgrading](upgrading.md).
|
package/docs/hosting.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Hosting the portal"
|
|
3
|
+
description: "Local is the default, and the honest options if you want it elsewhere."
|
|
4
|
+
sidebar_order: 11
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Hosting the portal
|
|
8
|
+
|
|
9
|
+
`roster portal` is local-first and that is the intended way to run it. It reads the checked-out
|
|
10
|
+
repositories from disk, needs no authentication, hits no API rate limits, and works offline.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
roster portal # http://localhost:4300
|
|
14
|
+
roster portal --port 4400
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Why local is the default
|
|
18
|
+
|
|
19
|
+
**Setup is local only.** The screen that stands up a tenant also creates GitHub Apps and writes
|
|
20
|
+
repository secrets, and none of that belongs behind a tunnel or an access proxy. Everything below
|
|
21
|
+
is about a portal over an org that already exists.
|
|
22
|
+
|
|
23
|
+
The portal can write. It replies to issues, closes them, reopens them and opens new ones,
|
|
24
|
+
acting as you through your own `gh`. That is the point: it is where a person answers their
|
|
25
|
+
agents. It also means it is not a thing to leave listening on a network.
|
|
26
|
+
|
|
27
|
+
Three things guard it, and they only work locally:
|
|
28
|
+
|
|
29
|
+
- it binds to `127.0.0.1`
|
|
30
|
+
- a write needs a `POST` with an `x-roster` header, which forces a CORS preflight that fails
|
|
31
|
+
from any other origin
|
|
32
|
+
- an `Origin` header, if present, must be localhost
|
|
33
|
+
|
|
34
|
+
`--host` overrides the bind address and prints a warning. Do not use it to "just have a look
|
|
35
|
+
from my phone".
|
|
36
|
+
|
|
37
|
+
## Reading it from elsewhere
|
|
38
|
+
|
|
39
|
+
The honest options, in order of how much you should like them.
|
|
40
|
+
|
|
41
|
+
**A tunnel, briefly.** `ssh -L 4300:localhost:4300 you@yourmachine`, or Tailscale, or
|
|
42
|
+
`cloudflared tunnel --url http://localhost:4300`. Your machine stays the only thing running it
|
|
43
|
+
and the write path stays behind your own network identity. Turn it off afterwards.
|
|
44
|
+
|
|
45
|
+
**A read-only static build.** `roster export` produces the whole org as one JSON document, and
|
|
46
|
+
the portal's rendering is decoupled from its parsing precisely so this is possible:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
roster export --out org.json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Serve that plus the portal HTML from anything static (Cloudflare Pages, S3, a directory). You
|
|
53
|
+
get memory, the graph, the brain and what-changed. You do not get the inbox or any write
|
|
54
|
+
action, because both need `gh`.
|
|
55
|
+
|
|
56
|
+
Put access control in front of it. Cloudflare Access with a one-person policy is the least
|
|
57
|
+
work. **This is private business content and a map of what your agents know**, so an
|
|
58
|
+
unauthenticated URL is not an option even if nobody knows it.
|
|
59
|
+
|
|
60
|
+
**A hosted instance with write access.** Not documented, and not recommended. It would need a
|
|
61
|
+
GitHub App of its own, a session layer, and a credible answer to "what can this thing do if
|
|
62
|
+
someone reaches it". None of that exists, and the local server plus a tunnel gets you the same
|
|
63
|
+
outcome with none of it.
|
|
64
|
+
|
|
65
|
+
## Keeping it current
|
|
66
|
+
|
|
67
|
+
The portal reads your working tree, so a stale checkout shows stale data. `/api/sync` fetches
|
|
68
|
+
and fast-forwards every repository on each refresh. It refuses to pull one that is dirty or has
|
|
69
|
+
diverged, and says which in a banner rather than guessing.
|
|
70
|
+
|
|
71
|
+
If you host a static export, the export is a point in time. Regenerate it on a schedule, or
|
|
72
|
+
accept that it is yesterday's.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Manual steps"
|
|
3
|
+
description: "Every human action, why it cannot be automated, and what breaks if you skip it."
|
|
4
|
+
sidebar_order: 2
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Manual steps
|
|
8
|
+
|
|
9
|
+
Everything a human has to do, why it cannot be automated, and what it looks like when you skip
|
|
10
|
+
it. This page exists because every item on it has cost somebody real time.
|
|
11
|
+
|
|
12
|
+
**The portal walks you through most of this now.** `roster` with no arguments opens a setup screen
|
|
13
|
+
that deep-links item 1, runs items 2 and 3 for you as far as GitHub allows, and hands you a prompt
|
|
14
|
+
for items 5 and 6. This page is still the *why*: it is what to read when one of them bites, and
|
|
15
|
+
what to check when the page says something is not done.
|
|
16
|
+
|
|
17
|
+
`roster doctor` checks most of these. Run it after each one.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Allow the ops repo's workflow to be called
|
|
22
|
+
|
|
23
|
+
**Do:** `<org>/roster-ops` -> Settings -> Actions -> General -> *Access* -> **Accessible from
|
|
24
|
+
repositories in the organisation**. The setup screen links straight to that page.
|
|
25
|
+
|
|
26
|
+
**Why not automated:** it is an organisation permission on a repository, and the API for it
|
|
27
|
+
needs admin rights that a token created for a different purpose should not have. roster reads
|
|
28
|
+
it and tells you, but setting it is one click and it is yours.
|
|
29
|
+
|
|
30
|
+
**If you skip it:** every caller fails with **"workflow not found"**. That reads like a typo in
|
|
31
|
+
a path, or a missing file, or a bad branch reference. You will check all three. It is none of
|
|
32
|
+
them, it is this.
|
|
33
|
+
|
|
34
|
+
**Check:** `roster doctor` reports `roster-ops is callable from the whole org`.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 2. Create the GitHub App
|
|
39
|
+
|
|
40
|
+
**Do:** the **GitHub App** button on a staff card in the portal, or `roster app <handle>` in a
|
|
41
|
+
terminal. Either opens a browser, GitHub asks you to confirm, and you come back. Credentials go
|
|
42
|
+
straight into the repository's secrets.
|
|
43
|
+
|
|
44
|
+
**Why not fully automated:** there is no API that creates a GitHub App. The only route is the
|
|
45
|
+
App Manifest flow: POST a manifest to a settings page, a human confirms, GitHub returns a
|
|
46
|
+
one-time code. roster does everything either side of that confirmation.
|
|
47
|
+
|
|
48
|
+
**If you skip it:** the run fails at the token-minting step with a message about the app not
|
|
49
|
+
existing.
|
|
50
|
+
|
|
51
|
+
**Note:** the private key is handed to `gh` on standard input. It is never written to a file,
|
|
52
|
+
never passed on a command line, and never appears in the process table. If the secret write
|
|
53
|
+
fails after the App is created, the key is gone: generate a new one from the App's settings
|
|
54
|
+
page and set the secret by hand. roster tells you this if it happens.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 3. Install the App, and grant it the right repositories
|
|
59
|
+
|
|
60
|
+
**Do:** open the URL the portal shows, or that `roster app` prints. Choose repositories.
|
|
61
|
+
|
|
62
|
+
**Why not automated:** installing is a grant of access to specific repositories, and GitHub
|
|
63
|
+
requires a human to choose them. This is the correct behaviour and should not be worked around.
|
|
64
|
+
|
|
65
|
+
**Grant it on every tracker the staff member writes to**, not just their own. The token is
|
|
66
|
+
minted organisation-wide, and a peer's board is where a brief lands. Both the portal and
|
|
67
|
+
`roster app` say so.
|
|
68
|
+
|
|
69
|
+
**If you skip it, or under-grant it:** this is the trap that costs the most time, because of
|
|
70
|
+
how it fails.
|
|
71
|
+
|
|
72
|
+
> The API reports an App's **declaration** separately from an installation's **grant**.
|
|
73
|
+
> `GET /apps/<slug>` will happily tell you the App exists and has `contents: write`. That says
|
|
74
|
+
> nothing about whether it has been installed on the repository you care about. Two of our
|
|
75
|
+
> Apps declare permissions they were never granted.
|
|
76
|
+
|
|
77
|
+
So: **do not verify an installation by reading the API.** The only thing that proves the whole
|
|
78
|
+
chain (App created, installed, granted, secrets right, workflow reachable) is a run that
|
|
79
|
+
finished. `roster doctor` reads a window of recent runs for exactly this reason, and reports a
|
|
80
|
+
workflow that has never run as **unproven** rather than as fine.
|
|
81
|
+
|
|
82
|
+
**Check:** `roster doctor <handle>`, then trigger one run and look again.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 4. Set the agent's credential
|
|
87
|
+
|
|
88
|
+
**Do:** put the coding agent's credential on each brain repo as a secret. The name follows the
|
|
89
|
+
credential: `CLAUDE_CODE_OAUTH_TOKEN`, `CODEX_API_KEY`, and so on. See
|
|
90
|
+
[choosing a coding agent](agents.md).
|
|
91
|
+
|
|
92
|
+
**Why not automated:** it is your account's credential and roster has no way to obtain one.
|
|
93
|
+
|
|
94
|
+
**If you skip it:** the run fails immediately with `the caller passed no agent credential`.
|
|
95
|
+
That check exists so it fails there rather than forty lines later inside the agent, after the
|
|
96
|
+
checkouts have already happened.
|
|
97
|
+
|
|
98
|
+
**Check:** `roster doctor` lists the secrets each caller references and whether they exist.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## 5. Write `org/business.md`
|
|
103
|
+
|
|
104
|
+
**Do:** answer the questions `roster init` leaves in it. The setup screen has a **Copy the
|
|
105
|
+
prompt** button that carries every file it refers to, and a box to paste the answer back into;
|
|
106
|
+
`roster brief discover` prints the same brief for a terminal.
|
|
107
|
+
|
|
108
|
+
`roster doctor` reports `business.stub` while it is still the questions.
|
|
109
|
+
|
|
110
|
+
**Why not automated:** an agent that does not know the business writes work that is plausible
|
|
111
|
+
and generic. That is worse than no work, because it takes longer to notice. This file is
|
|
112
|
+
composed into the top of every prompt, every run.
|
|
113
|
+
|
|
114
|
+
**If you skip it:** nothing errors. That is the problem. You get competent-looking output about
|
|
115
|
+
a business that does not exist.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## 6. Write each staff member's `CHARTER.md`
|
|
120
|
+
|
|
121
|
+
**Do:** **Write the charter** on that staff member's card in the portal, or
|
|
122
|
+
`roster brief charter <handle>` and paste it into your agent. Or write it by hand;
|
|
123
|
+
[writing a charter](writing-a-charter.md) has the shape.
|
|
124
|
+
|
|
125
|
+
**Why not automated:** same reason, one level down. The charter is what makes a staff member
|
|
126
|
+
different from the others.
|
|
127
|
+
|
|
128
|
+
**If you skip it:** `charter` reports it as present, because the stub is a file. `charter.stub`
|
|
129
|
+
is the finding that says nobody has answered it. The agent has no personality and produces
|
|
130
|
+
whatever the shared layer implies.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 7. Commit and push what roster wrote into other repos
|
|
135
|
+
|
|
136
|
+
**Do:** `roster hire` and `roster upgrade` write into brain repos on disk. Review, commit, push.
|
|
137
|
+
|
|
138
|
+
**Why not automated:** roster does not commit on your behalf into repositories it did not
|
|
139
|
+
create in that command. And **App tokens cannot push a change under `.github/workflows/` in any
|
|
140
|
+
repository**, which is a GitHub restriction and not a configuration mistake. That is also why
|
|
141
|
+
agents can never update their own workflows, and why upgrades are human-run by design.
|
|
142
|
+
|
|
143
|
+
**If you skip it:** the change exists locally and nowhere else. `roster upgrade` will report it
|
|
144
|
+
as still pending next time, which is the intended behaviour.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Order
|
|
149
|
+
|
|
150
|
+
For a new organisation:
|
|
151
|
+
|
|
152
|
+
In the portal, this order is the screen you are looking at. From a terminal:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
roster init --org <org> --apply # 1 applies here
|
|
156
|
+
roster hire <handle> --apply # then 7
|
|
157
|
+
roster app <handle> # 2, then 3
|
|
158
|
+
# 4, 5, 6
|
|
159
|
+
roster doctor <handle>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Then trigger one run by hand before trusting the schedule. A workflow that has never run has
|
|
163
|
+
proved nothing.
|
package/docs/memory.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Memory"
|
|
3
|
+
description: "The grammar, the five rules, and why deleting is the maintenance."
|
|
4
|
+
sidebar_order: 7
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Memory
|
|
8
|
+
|
|
9
|
+
A staff member's memory is markdown in its own repository. There is no database, deliberately:
|
|
10
|
+
an agent writes markdown well and writes to a schema badly.
|
|
11
|
+
|
|
12
|
+
## The two files
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
memory/INDEX.md one line per fact. Read in full at every boot.
|
|
16
|
+
memory/notes/*.md the argument behind a fact. Read only when that fact is in play.
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
That split is the whole design. Boot context here went from about 52,000 words to about 6,000
|
|
20
|
+
by making it, and the saving repeats on every run forever.
|
|
21
|
+
|
|
22
|
+
## The grammar
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
- **`<slug>`** · [<will|measured|derived>] <the fact, one line>. **So:** <what it changes>. · [note](notes/<slug>.md)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`roster lint` enforces it, and the portal parses it. Provenance and the note link are optional.
|
|
29
|
+
The slug, the fact and the `So:` are not.
|
|
30
|
+
|
|
31
|
+
**Provenance** is one of three things: a human ruled it, it was measured, or it was derived.
|
|
32
|
+
A `[measured]` fact without an `n` fails lint, because a number without a sample size is a
|
|
33
|
+
rumour.
|
|
34
|
+
|
|
35
|
+
## The five rules
|
|
36
|
+
|
|
37
|
+
1. **One line per fact.** If it needs more, the extra goes in `notes/<slug>.md` and the line
|
|
38
|
+
stays one line.
|
|
39
|
+
2. **Correct in place. Never append "updated:".** An update chain is how one fact becomes six
|
|
40
|
+
paragraphs that contradict each other.
|
|
41
|
+
3. **Every fact says what it changes.** If you cannot write the `So:`, it is not memory. Do not
|
|
42
|
+
add it.
|
|
43
|
+
4. **Measurements carry `n` and a date. Constraints do not expire; measurements do.** Anything
|
|
44
|
+
with a `review:` date is re-read or deleted on that date.
|
|
45
|
+
5. **Deleting is the maintenance.** Cut every line that no longer changes a decision, and log
|
|
46
|
+
the cut. A memory that only grows is a memory nobody reads.
|
|
47
|
+
|
|
48
|
+
Rule 5 is the one that gets skipped and the one that matters. Everything else degrades slowly;
|
|
49
|
+
this one degrades the boot cost of every future run.
|
|
50
|
+
|
|
51
|
+
## What does not go in memory
|
|
52
|
+
|
|
53
|
+
- **Why something was decided.** That is `log/decisions.md`, and it is not boot context.
|
|
54
|
+
- **How a thing works.** That is a draft or a strategy document.
|
|
55
|
+
- **What is outstanding.** That is the pinned status issue.
|
|
56
|
+
|
|
57
|
+
Nothing is copied between them. Four places, four jobs, and a fact that appears in two of them
|
|
58
|
+
will disagree with itself within a month.
|
|
59
|
+
|
|
60
|
+
## Checking it
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
roster lint # everyone
|
|
64
|
+
roster lint cto # one staff member
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Lint catches: a missing `So:`, a duplicate slug, a note nothing links to, a link to a note that
|
|
68
|
+
does not exist, an over-long line, a `[measured]` fact with no `n`, and an "updated:" chain.
|
|
69
|
+
|
|
70
|
+
The portal's **Health** screen shows the same findings and will open an issue in the staff
|
|
71
|
+
member's own repository asking them to fix it, which is usually the right move: they wrote it.
|
package/docs/org-yaml.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "org.yaml reference"
|
|
3
|
+
description: "Every field in the org manifest, and what reads it."
|
|
4
|
+
sidebar_order: 13
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# `org.yaml` reference
|
|
8
|
+
|
|
9
|
+
The org manifest. Lives at the root of the ops repo, and is read at the top of every composed
|
|
10
|
+
prompt, by `runner-plan.mjs`, by `agents.mjs`, and by every CLI command.
|
|
11
|
+
|
|
12
|
+
Parsed by `parseYaml` in `compose.mjs`, which reads a deliberately small, strict subset of
|
|
13
|
+
YAML: scalars, nested maps, block lists, and inline maps in a list. It does not do anchors,
|
|
14
|
+
multi-line scalars, or flow maps at the top level. **A manifest that needs more than that has
|
|
15
|
+
outgrown being a manifest**, and the parser refuses to guess rather than misparsing.
|
|
16
|
+
|
|
17
|
+
## A complete example
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
org: acme
|
|
21
|
+
name: Acme Robotics
|
|
22
|
+
ops_dir: roster-ops
|
|
23
|
+
|
|
24
|
+
human:
|
|
25
|
+
name: Will
|
|
26
|
+
github: you
|
|
27
|
+
marker: will
|
|
28
|
+
role: founder
|
|
29
|
+
|
|
30
|
+
experiment_private: true
|
|
31
|
+
|
|
32
|
+
agent:
|
|
33
|
+
id: claude-code-action
|
|
34
|
+
|
|
35
|
+
defaults:
|
|
36
|
+
model: claude-opus-5
|
|
37
|
+
timeout_minutes: 60
|
|
38
|
+
allowed_tools: [Bash, Read, Write, Edit, Glob, Grep, WebFetch, WebSearch]
|
|
39
|
+
|
|
40
|
+
staff:
|
|
41
|
+
- { handle: cto, dir: technology, name: Chief Technology Officer, schedule: "0 7 * * 1-5" }
|
|
42
|
+
- { handle: cmo, dir: marketing, name: Chief Marketing Officer, schedule: "40 7 * * 1-5" }
|
|
43
|
+
|
|
44
|
+
repos:
|
|
45
|
+
- { name: acme-web, visibility: public, role: product }
|
|
46
|
+
- { name: technology, visibility: private, role: brain }
|
|
47
|
+
- { name: roster-ops, visibility: private, role: ops }
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Fields
|
|
51
|
+
|
|
52
|
+
### Top level
|
|
53
|
+
|
|
54
|
+
| Field | Required | Means |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `org` | yes | The GitHub organisation. Every repo name is resolved against it. |
|
|
57
|
+
| `name` | yes | What the business is called, in prose. Appears in prompts. |
|
|
58
|
+
| `ops_dir` | no | Directory name of the ops repo in the runner checkout. Defaults to `roster-ops`. |
|
|
59
|
+
| `experiment_private` | no | Whether the fact that this org is agent-run is itself private. Read by the guardrails fragment. |
|
|
60
|
+
|
|
61
|
+
### `human`
|
|
62
|
+
|
|
63
|
+
Who the staff answer to. There is exactly one.
|
|
64
|
+
|
|
65
|
+
| Field | Required | Means |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `github` | yes | Login. **The mention callers gate on this**, so without it nothing can wake an agent. |
|
|
68
|
+
| `name` | no | What to call them in prose. Defaults to the login. |
|
|
69
|
+
| `marker` | no | Provenance tag on a fact they ruled on, as in `[will]`. Also used as a label. |
|
|
70
|
+
| `role` | no | Prose only. |
|
|
71
|
+
|
|
72
|
+
### `agent`
|
|
73
|
+
|
|
74
|
+
Which coding agent runs a session. Either a string, or a map. See
|
|
75
|
+
[choosing a coding agent](agents.md).
|
|
76
|
+
|
|
77
|
+
| Field | Required | Means |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `id` | no | A preset name, or your own label. Defaults to `claude-code-action`. |
|
|
80
|
+
| `install` | if `id` is unknown | Shell command that installs the agent on the runner. |
|
|
81
|
+
| `run` | if `id` is unknown | Shell command that runs it, reading `$AGENT_PROMPT_FILE`. |
|
|
82
|
+
| `token_env` | if `id` is unknown | Environment variable its credential goes in. |
|
|
83
|
+
| `model` | no | Default model for this agent. A staff member's own `model` wins. |
|
|
84
|
+
|
|
85
|
+
Any field given overrides the preset's, so a preset that is right except for one flag needs
|
|
86
|
+
one line.
|
|
87
|
+
|
|
88
|
+
### `defaults`
|
|
89
|
+
|
|
90
|
+
Fallbacks for staff members who do not set their own.
|
|
91
|
+
|
|
92
|
+
| Field | Means |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `model` | Model id passed to the agent. |
|
|
95
|
+
| `timeout_minutes` | Ceiling on a daily session. |
|
|
96
|
+
| `allowed_tools` | Tool permission string. Meaningful to agents that take one, ignored by those that do not. |
|
|
97
|
+
|
|
98
|
+
### `staff`
|
|
99
|
+
|
|
100
|
+
The registry. One inline map per staff member. **This is the org's view of them**; the rest
|
|
101
|
+
lives in their own `staff.yaml`.
|
|
102
|
+
|
|
103
|
+
| Field | Required | Means |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| `handle` | yes | Short identifier. Must match the handle in their manifest. |
|
|
106
|
+
| `dir` | no | Directory and repo name. Defaults to the handle. |
|
|
107
|
+
| `name` | no | Role name in prose. |
|
|
108
|
+
| `schedule` | no | Cron. Informational here; the caller workflow is what actually schedules. |
|
|
109
|
+
|
|
110
|
+
`roster hire` appends to this list. An empty list (`staff: []`) is valid and is what a fresh
|
|
111
|
+
org has.
|
|
112
|
+
|
|
113
|
+
### `repos`
|
|
114
|
+
|
|
115
|
+
Every repository the org owns, and what it is for.
|
|
116
|
+
|
|
117
|
+
| Field | Means |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `name` | Repo name, resolved against `org`. |
|
|
120
|
+
| `visibility` | `public` or `private`. `roster doctor` warns when this disagrees with reality. |
|
|
121
|
+
| `role` | `brain`, `product` or `ops`. |
|
|
122
|
+
|
|
123
|
+
`role: product` is load-bearing: `roster hire` uses it to fill a new staff member's
|
|
124
|
+
`works_in`, and the prompts refer to the product repo by name.
|
|
125
|
+
|
|
126
|
+
## What reads what
|
|
127
|
+
|
|
128
|
+
| Reader | Uses |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `compose.mjs` | `org`, `name`, `human`, `ops_dir`, `staff` |
|
|
131
|
+
| `runner-plan.mjs` | `org`, `staff`, and each manifest's `works_in` and `peers` |
|
|
132
|
+
| `agents.mjs` | `agent`, `staff` |
|
|
133
|
+
| `roster hire` | all of it, plus every existing manifest |
|
|
134
|
+
| `roster doctor` | all of it |
|
|
135
|
+
|
|
136
|
+
## Editing it
|
|
137
|
+
|
|
138
|
+
It is yours. `roster upgrade` never touches it: it has no template, because a tenant's registry
|
|
139
|
+
is not something a framework can have an opinion about.
|
|
140
|
+
|
|
141
|
+
The exception is `roster hire --apply`, which appends a `staff` entry and a `repos` entry.
|
|
142
|
+
Those are inserted textually under the existing keys rather than by re-serialising the file,
|
|
143
|
+
so your comments and formatting survive.
|