@nidvue/teamwork 0.0.0-stage → 1.1.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/CHANGELOG.md +343 -0
- package/LICENSE +661 -0
- package/NOTICE +16 -0
- package/README.md +462 -2
- package/SECURITY.md +64 -0
- package/package.json +71 -4
- package/prompts/teamwork-pulse.md +12 -0
- package/prompts/teamwork-review.md +16 -0
- package/skills/teamwork/AGENTS.md +462 -0
- package/skills/teamwork/SKILL.md +795 -0
- package/skills/teamwork/references/Adapters.md +112 -0
- package/skills/teamwork/references/Audit.md +120 -0
- package/skills/teamwork/references/Concurrency.md +160 -0
- package/skills/teamwork/references/Dissent.md +85 -0
- package/skills/teamwork/references/Docs.md +74 -0
- package/skills/teamwork/references/Engineering.md +410 -0
- package/skills/teamwork/references/Evidence.md +140 -0
- package/skills/teamwork/references/Remotes.md +144 -0
- package/skills/teamwork/references/Roles.md +201 -0
- package/skills/teamwork/references/State.md +64 -0
- package/skills/teamwork/references/Testing.md +144 -0
- package/skills/teamwork/roles/architect.md +153 -0
- package/skills/teamwork/roles/ceo.md +218 -0
- package/skills/teamwork/roles/cfo.md +150 -0
- package/skills/teamwork/roles/coo.md +147 -0
- package/skills/teamwork/roles/cto.md +162 -0
- package/skills/teamwork/roles/data-engineer.md +120 -0
- package/skills/teamwork/roles/designer.md +349 -0
- package/skills/teamwork/roles/developer.md +166 -0
- package/skills/teamwork/roles/product-manager.md +151 -0
- package/skills/teamwork/roles/project-manager.md +159 -0
- package/skills/teamwork/roles/release-engineer.md +245 -0
- package/skills/teamwork/roles/reviewer.md +254 -0
- package/skills/teamwork/roles/security-auditor.md +157 -0
- package/skills/teamwork/roles/technical-writer.md +121 -0
- package/skills/teamwork/roles/tester.md +180 -0
- package/skills/teamwork/scripts/build_pi_package.py +200 -0
- package/skills/teamwork/scripts/privacy_scan.py +1185 -0
- package/skills/teamwork/scripts/sync_skill.py +108 -0
- package/skills/teamwork/scripts/teamwork.py +28 -0
- package/skills/teamwork/scripts/verify_release.py +502 -0
- package/skills/teamwork/src/teamwork/__init__.py +18 -0
- package/skills/teamwork/src/teamwork/__main__.py +10 -0
- package/skills/teamwork/src/teamwork/bundle.py +157 -0
- package/skills/teamwork/src/teamwork/cli.py +16 -0
- package/skills/teamwork/src/teamwork/config.py +396 -0
- package/skills/teamwork/src/teamwork/engine.py +10119 -0
- package/skills/teamwork/src/teamwork/gitutil.py +172 -0
- package/skills/teamwork/src/teamwork/imaging.py +124 -0
- package/skills/teamwork/src/teamwork/io.py +144 -0
- package/skills/teamwork/src/teamwork/layout.py +253 -0
- package/skills/teamwork/src/teamwork/names.py +191 -0
- package/skills/teamwork/src/teamwork/portable.py +79 -0
- package/skills/teamwork/src/teamwork/records.py +1220 -0
- package/skills/teamwork/src/teamwork/resources.py +120 -0
- package/skills/teamwork/src/teamwork/version.py +13 -0
- package/skills/teamwork/templates/AGENTS.md +460 -0
- package/skills/teamwork/templates/Docs/Architecture.md +40 -0
- package/skills/teamwork/templates/Docs/Archive.md +8 -0
- package/skills/teamwork/templates/Docs/Board.md +28 -0
- package/skills/teamwork/templates/Docs/Costs.md +30 -0
- package/skills/teamwork/templates/Docs/Decisions.md +26 -0
- package/skills/teamwork/templates/Docs/Design.md +106 -0
- package/skills/teamwork/templates/Docs/Plan.md +24 -0
- package/skills/teamwork/templates/Docs/Project.md +40 -0
- package/skills/teamwork/templates/Docs/Release.md +43 -0
- package/skills/teamwork/templates/Docs/Research.md +36 -0
- package/skills/teamwork/templates/Docs/Risks.md +18 -0
- package/skills/teamwork/templates/TeamMap.md +100 -0
- package/skills/teamwork-pi/SKILL.md +77 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Adapters - running the team on any agent host
|
|
2
|
+
|
|
3
|
+
The team is a **protocol**, not a product feature. Everything normative in this
|
|
4
|
+
skill - the workspace format, acceptance-criteria records, the two-stage gate,
|
|
5
|
+
the hash-chained ledger, the test-layer matrix, `AGENTS.md` - is host-independent
|
|
6
|
+
and lives in files the team owns. Only six operations need a host to provide a
|
|
7
|
+
mechanism, and this file maps each one to the concrete tool of a given host.
|
|
8
|
+
|
|
9
|
+
Never hard-code a host tool in a normative step. Name the operation, then use the
|
|
10
|
+
adapter. If a host cannot provide an operation, use its documented degraded mode -
|
|
11
|
+
the gates still hold, only the concurrency drops.
|
|
12
|
+
|
|
13
|
+
This file is the only **adoption surface** that names a concrete host. Every other surface
|
|
14
|
+
(`SKILL.md`, README, install guide, quickstart) describes one generic protocol and
|
|
15
|
+
points here, so a new host is a new column, never a rewrite of the instructions.
|
|
16
|
+
|
|
17
|
+
## The six operations
|
|
18
|
+
|
|
19
|
+
| # | Operation | What the team needs |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| 1 | **Spawn a teammate** | start a long-lived agent with a persona and its own context |
|
|
22
|
+
| 2 | **Delegate one-shot work** | run a bounded, isolated task and take its result |
|
|
23
|
+
| 3 | **Message an agent** | send a direct or broadcast instruction |
|
|
24
|
+
| 4 | **Inspect teammate state** | see who is idle, busy, stuck; read their last output |
|
|
25
|
+
| 5 | **Re-wake on a schedule** (pulse) | periodic trigger to feed idle lanes |
|
|
26
|
+
| 6 | **Close the team** | stop the teammates and release the lanes |
|
|
27
|
+
|
|
28
|
+
## Host mapping
|
|
29
|
+
|
|
30
|
+
| Operation | Pi | Claude Code | opencode | Codex / Cursor / Windsurf / Gemini CLI | Generic (no agent runtime) |
|
|
31
|
+
|---|---|---|---|---|---|
|
|
32
|
+
| 1 spawn | `subagent({agent, task})` - one call per lane, `async: true` keeps the CEO free while it runs; a *persistent* teammate needs a teams-style extension, the default host gives bounded runs | `Agent`/`Task` tool with a `.claude/agents/<name>.md` persona | `.opencode/agent/<name>.md` + the Task tool | run the CLI as a subprocess (`codex exec`, `cursor-agent`) | `bash` background process + a prompt file |
|
|
33
|
+
| 2 one-shot | `subagent({agent,task})` | `Task` tool, single agent | Task tool / a separate `opencode run` | `codex exec "<task>"` | one `bash` invocation, result to a file |
|
|
34
|
+
| 3 message | child to parent: `contact_supervisor` / `subagent_supervisor({action:"reply"})`; parent to child: `subagent({action:"steer"/"resume", id, message})` | `SendMessage` / prompt injection | agent-to-agent message | write to the agent's inbox file | append to `Agents/<Name>/Inbox.md` |
|
|
35
|
+
| 4 inspect | `subagent({action:"status", id})` and `subagent_supervisor({action:"list"/"pending"})` for the runs | agent status / task list | session list | process list + worklog | `teamwork.py board` + `pulse` + `WorkLog.md` |
|
|
36
|
+
| 5 pulse | `subagent({action:"schedule.create", options:{every:"5m"}})` | no built-in scheduler: `Bash` background loop, `/loop`, or host `cron` running `claude -p` | no scheduler: `cron`/systemd running `opencode run` | host `cron` / `watch` / CI schedule | `cron`, `systemd` timer, or a `while` loop running `teamwork.py pulse --commit` |
|
|
37
|
+
| 6 close | a bounded run ends with its own task; stop a live one with `subagent({action:"stop", id})` and list what still runs with `subagent_supervisor({action:"list"})` | stop the subagents / end the session | stop sessions | kill the processes | `pkill` the lanes, `teamwork.py clean` |
|
|
38
|
+
| skill install | `~/.pi/agent/skills/<name>/SKILL.md` | `.claude/skills/<name>/SKILL.md` (Agent Skills format - this file already matches: `name` + `description` frontmatter) | `AGENTS.md` + `.opencode/command/<name>.md` | `AGENTS.md` (every one of these reads it) | `AGENTS.md` + this directory |
|
|
39
|
+
|
|
40
|
+
The Pi column was verified against the installed `pi-subagents` package on
|
|
41
|
+
2026-10-19 (pi 1.3.0): it exposes `subagent`, `subagents_enable`,
|
|
42
|
+
`subagent_supervisor`, `contact_supervisor` and `structured_output`, and **no
|
|
43
|
+
`teams(...)` tool**. A host that does provide a teams-style tool maps the same
|
|
44
|
+
four operations to
|
|
45
|
+
`teams({action:"delegate"/"message_dm"/"member_status"/"team_done"})`.
|
|
46
|
+
|
|
47
|
+
`AGENTS.md` at the project root is the universal contract: Claude Code, opencode,
|
|
48
|
+
Codex, Cursor, Windsurf, Gemini CLI, Aider and Pi all read it. Write the team
|
|
49
|
+
constitution there once (`teamwork.py agents-md`) and every host inherits it.
|
|
50
|
+
|
|
51
|
+
## Degraded modes (still complete, just slower)
|
|
52
|
+
|
|
53
|
+
- **No scheduler** (operation 5): run `teamwork.py pulse --commit` on a host `cron`
|
|
54
|
+
entry, or have the CEO re-issue the pulse prompt at milestones, or simply have
|
|
55
|
+
each lane self-serve with `teamwork.py task next <name>` between turns. The rule
|
|
56
|
+
"never let an idle lane sit while runnable work exists" is unchanged; only the
|
|
57
|
+
automation of the wake-up differs.
|
|
58
|
+
- **No teammate tool** (operation 1/2): the same role charters are executed
|
|
59
|
+
sequentially by one agent that switches hats, claiming tasks from the same
|
|
60
|
+
shared queues. The evidence gates, the Reviewer separation and the ledger are
|
|
61
|
+
unaffected - which is the point: the protocol does not depend on parallelism.
|
|
62
|
+
- **No message tool** (operation 3): the mailbox is already a file
|
|
63
|
+
(`Agents/<Name>/Inbox.md`); writing to it is a valid message on every host.
|
|
64
|
+
- **No `teams` tool**: spawn with the host's own CLI in a `bash` job and point it
|
|
65
|
+
at `Agents/<Name>/StartHere.md` - the startup routine is identical.
|
|
66
|
+
- **Only bounded runs** (Pi's `subagent`, a CLI job): fan the lanes out as
|
|
67
|
+
concurrent calls instead of persistent teammates - one Reviewer instance per
|
|
68
|
+
call, each starting from its own `StartHere.md`. Bounded runs cannot see each
|
|
69
|
+
other, so the **board is what keeps them apart**: the CEO fans deliverables out
|
|
70
|
+
with `pulse --commit` and every lane takes work with
|
|
71
|
+
`review ... --claim --by <lane>` / `task next`, which is exactly why a claim is
|
|
72
|
+
a record and not a handshake. Two Reviewer lanes that skip the claim will
|
|
73
|
+
review the same deliverable twice.
|
|
74
|
+
|
|
75
|
+
## Host detection also drives model routing
|
|
76
|
+
|
|
77
|
+
The same detection that picks the adapter picks the model: `teamwork.py model auto`
|
|
78
|
+
reads the host (pi, claude, opencode, codex, cursor, gemini) and the model that host
|
|
79
|
+
exposes, then routes the strongest available model to the decision lanes and the
|
|
80
|
+
economy model to the mechanical lanes; `TEAMWORK_AGENT_HOST` pins the detection when
|
|
81
|
+
the markers are ambiguous. Policy: [Concurrency](Concurrency.md).
|
|
82
|
+
|
|
83
|
+
## The skill copy is the thing that runs
|
|
84
|
+
|
|
85
|
+
Every host reads a *copy* of this skill from its skills directory, so the copy has
|
|
86
|
+
to follow the remote. One command owns that on every host:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
teamwork refresh # fetch origin/main, then mirror into the host's skills dir
|
|
90
|
+
teamwork refresh --check # drift only, writes nothing, exit 1 when stale
|
|
91
|
+
teamwork refresh --dest ~/.agents/skills/teamwork # another host's directory
|
|
92
|
+
teamwork refresh --mirror --repo <url> # no checkout yet: create the mirror once
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Measured failure this prevents: a host copy with an old `SKILL.md` and eight
|
|
96
|
+
engine modules missing - the engine imported `config`/`gitutil`/`records` fine
|
|
97
|
+
from the checkout and failed from the installed copy. A dirty checkout is
|
|
98
|
+
mirrored, never reset; files the source dropped are deleted; a host reload is
|
|
99
|
+
required after a write and the command says so.
|
|
100
|
+
|
|
101
|
+
## Rules
|
|
102
|
+
|
|
103
|
+
1. **The engine is the constant.** `teamwork.py` (stdlib only, Python 3.9-3.13) is
|
|
104
|
+
the only thing a host must be able to run. It never calls a host API.
|
|
105
|
+
2. **State lives in git and in `.pi/`.** Nothing important lives in a host's
|
|
106
|
+
private memory: a teammate that dies and is respawned on another host resumes
|
|
107
|
+
from `StartHere.md`, the task queue and the ledger.
|
|
108
|
+
3. **One voice to the user** stays true on every host: only the CEO reports.
|
|
109
|
+
4. **A missing capability is not a red line.** Record the adapter used and the
|
|
110
|
+
degradation in the task evidence; never fake a tool call that the host lacks.
|
|
111
|
+
5. **Adding a host** means adding a column here plus a smoke test that the six
|
|
112
|
+
operations exist in some form - not changing the protocol.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Recording, traceability and audit
|
|
2
|
+
|
|
3
|
+
Reference for the /teamwork skill. Loaded on demand.
|
|
4
|
+
|
|
5
|
+
Related: [Evidence](Evidence.md) | [Roles](Roles.md) | [Engineering](Engineering.md) | [State](State.md) | [Docs](Docs.md) | [Testing](Testing.md) | [Concurrency](Concurrency.md)
|
|
6
|
+
|
|
7
|
+
## What is recorded
|
|
8
|
+
|
|
9
|
+
Every piece of state is a record with provenance, not a note in a chat:
|
|
10
|
+
|
|
11
|
+
| Record | Where | Provenance |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| Memory entry | `Roles/<Role>/ShortTermMemory.md`, `LongTermMemory.md` | `by`, `src`, `rev` on every entry |
|
|
14
|
+
| Task | `Roles/<Role>/TaskQueue.md` | `claimed_by`, `branch`, `pr`, `area`, `evidence`, `reviewer`, `merge_commit`, `forced` |
|
|
15
|
+
| Acceptance criterion | `Criteria.md` | owner + the verifying instance and its evidence |
|
|
16
|
+
| Test layer | `Tests.md`, `TestPlan.md` | owner role, runner, command, evidence, revision |
|
|
17
|
+
| Review / PR | `Reviews.md` | author, branch, reviewer, verdict, merge revision |
|
|
18
|
+
| Dispute | `Disputes.md` | raiser, opponent, every round, signatures, ruling |
|
|
19
|
+
| Decision | `docs/Team/Decisions.md` | decider, evidence, falsifier, consequences |
|
|
20
|
+
| Accepted result | `docs/Team/Archive.md` | what shipped, by which instance, verified how, at which revision |
|
|
21
|
+
| **Every mutation** | `Ledger.jsonl` | timestamp, actor, role, action, target, detail, revision |
|
|
22
|
+
|
|
23
|
+
Nothing is written without naming who wrote it and what it came from.
|
|
24
|
+
|
|
25
|
+
## The ledger
|
|
26
|
+
|
|
27
|
+
`Ledger.jsonl` is append-only. Each line is one record:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{"ts":"2026-10-17T20:08:43","n":7,"actor":"developer-1","role":"developer",
|
|
31
|
+
"action":"commit","target":"T-0001","detail":"feat(auth): src/auth.py | 2 file(s) e257f69",
|
|
32
|
+
"rev":"e257f69","prev":"<hash of record 6>","hash":"<sha256(prev + canonical record)>"}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`hash = sha256(prev_hash + canonical_json(record))`, so records are chained: editing
|
|
36
|
+
or deleting any line breaks every hash after it.
|
|
37
|
+
|
|
38
|
+
Actions cover the whole lifecycle: `memory.add|update|promote|drop|merge|evict`,
|
|
39
|
+
`task.add|claim|status|evidence|reclaim`, `selfcheck`, `review.pass|fail`,
|
|
40
|
+
`pr.open|merge`, `branch.start|retire`, `criteria.add|verify`, `tests.add|run`,
|
|
41
|
+
`dispute.open|round|escalate|sign|resolve`, `decision.add`, `commit`, `ledger.export`.
|
|
42
|
+
|
|
43
|
+
Memory maintenance is logged too, so a fact never disappears silently: promotion,
|
|
44
|
+
dropping, key-merging and archive eviction each write a record with the entry key.
|
|
45
|
+
|
|
46
|
+
## Internal audit
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
teamwork.py trace <T-id|AC-id|TS-id|P-id> # one claim, end to end
|
|
50
|
+
teamwork.py ledger show --tail 40 [--action review.pass] [--actor reviewer-1]
|
|
51
|
+
teamwork.py ledger verify # recompute the chain
|
|
52
|
+
teamwork.py audit # trail health + provenance + coverage
|
|
53
|
+
teamwork.py loop # a broken trail blocks STOP
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`trace` joins the task, its commits, the PR, the review, the tests, the criteria and
|
|
57
|
+
the ledger events into one chronological view: claim -> evidence -> commit -> review
|
|
58
|
+
-> merge -> archive.
|
|
59
|
+
|
|
60
|
+
`audit` reports: chain problems, memory entries without `by` provenance, decisions
|
|
61
|
+
without evidence, a ledger that shrank since the last export, plus the usual gates,
|
|
62
|
+
coverage and branch checks.
|
|
63
|
+
|
|
64
|
+
## External audit
|
|
65
|
+
|
|
66
|
+
`teamwork.py ledger export` writes two committed artifacts that a third party can
|
|
67
|
+
check **without trusting the team**:
|
|
68
|
+
|
|
69
|
+
- `docs/Team/AuditManifest.json` - team, project, git revision and branch, ledger
|
|
70
|
+
record count and head hash, a sha256 digest for every committed state artifact
|
|
71
|
+
except `docs/Team/Archive.md` (append-only: it gains an entry when a review
|
|
72
|
+
passes, so a digest committed beside it would be stale by construction; its
|
|
73
|
+
entries are followed through the ledger), and the exact verification steps.
|
|
74
|
+
- `docs/Team/AuditReport.md` - the human summary of the same facts.
|
|
75
|
+
|
|
76
|
+
Verification procedure (reproducible by anyone with the repository):
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
teamwork.py ledger verify --reconcile # recompute the chain; a head cache left
|
|
80
|
+
# behind by a crash is repaired, a removal
|
|
81
|
+
# of records is reported
|
|
82
|
+
teamwork.py ledger repair --by <instance> --reason "<why>" # drop a torn tail
|
|
83
|
+
sha256sum -c <(jq -r '.artifacts[] | "\(.sha256) \(.path)"' docs/Team/AuditManifest.json)
|
|
84
|
+
git cat-file -t <git.head> # the reviewed revision still exists
|
|
85
|
+
teamwork.py trace <T-id> # follow any individual claim
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
What each check proves:
|
|
89
|
+
|
|
90
|
+
| Check | Proves |
|
|
91
|
+
|---|---|
|
|
92
|
+
| hash chain + head hash | the trail was not edited, reordered or truncated after export |
|
|
93
|
+
| `verify --reconcile` | a crash artefact is distinguishable from tampering: a stale cache is repaired, a *shrinking* ledger is reported |
|
|
94
|
+
| `ledger repair` | a torn tail is recoverable, and the repair itself is a logged record |
|
|
95
|
+
| artifact digests | the records themselves are byte-identical to the reviewed state |
|
|
96
|
+
| git revision | the work that was accepted is the work that exists |
|
|
97
|
+
| per-record provenance | every claim can be attributed to an instance, a role and a revision |
|
|
98
|
+
|
|
99
|
+
The manifest separates **externally verifiable** artifacts (committed project
|
|
100
|
+
output under `docs/Team/`) from **local_state** (hidden working state under
|
|
101
|
+
`.pi/`, only checkable on the machine that produced it). The export records its own
|
|
102
|
+
`ledger.export` event *before* capturing the checkpoint, so `ledger verify` after
|
|
103
|
+
an export matches the manifest exactly.
|
|
104
|
+
|
|
105
|
+
`AuditManifest.json` should be committed with the milestone it covers (the Reviewer
|
|
106
|
+
can include it in the `chore(records)` commit), so the head hash becomes a
|
|
107
|
+
checkpoint in git history - and a later truncation of the ledger is then detected
|
|
108
|
+
by comparing against it.
|
|
109
|
+
|
|
110
|
+
## Honest limits
|
|
111
|
+
|
|
112
|
+
- The ledger is tamper-**evident**, not tamper-**proof**: anyone with write access
|
|
113
|
+
can rebuild it, but they cannot reproduce the exported head hash without also
|
|
114
|
+
rewriting the committed manifest, and the manifest's git history is append-only.
|
|
115
|
+
- Identity is accountability, not cryptography: `--by` names an existing instance,
|
|
116
|
+
and every action it performs is recorded against it. It does not prove which OS
|
|
117
|
+
process typed the command.
|
|
118
|
+
- A record proves that something was declared, with the evidence that was given.
|
|
119
|
+
Whether the evidence proves the claim is what the Reviewer and `criteria verify`
|
|
120
|
+
are for: both require an independent role.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Concurrency and reuse
|
|
2
|
+
|
|
3
|
+
Reference for the /teamwork skill. Loaded on demand; `SKILL.md` keeps the
|
|
4
|
+
operating procedure.
|
|
5
|
+
|
|
6
|
+
Related: [Engineering](Engineering.md) | [Evidence](Evidence.md) | [Docs](Docs.md) | [State](State.md) | [Concurrency](Concurrency.md) | [Roles](Roles.md) | [Testing](Testing.md) | [Audit](Audit.md)
|
|
7
|
+
|
|
8
|
+
## Concurrency budget and resource reuse
|
|
9
|
+
|
|
10
|
+
Run everything as parallel as the providers allow, never past their caps.
|
|
11
|
+
|
|
12
|
+
| Provider | Concurrent agents | Use it for |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| Ollama Cloud | 64 | focused reasoning lanes: architecture, review, disputes, analysis |
|
|
15
|
+
| DeepSeek official API | ~2500 | wide independent fanout: many developer/tester/designer sub-tasks, bulk docs and research |
|
|
16
|
+
|
|
17
|
+
Caps live in `.pi/Teamwork/Teams/<Team>/Settings.json` and are overridable with
|
|
18
|
+
`TEAMWORK_PROVIDER_LIMITS="ollama-cloud=64,deepseek=2500"`.
|
|
19
|
+
|
|
20
|
+
### Slots are leases
|
|
21
|
+
|
|
22
|
+
Every model-heavy task holds a lease in `.pi/Teamwork/Teams/<Team>/Runtime/Slots/<provider>/`.
|
|
23
|
+
Leases expire after `TEAMWORK_SLOT_TTL_MINUTES` (90) so a crashed lane cannot
|
|
24
|
+
leak capacity.
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
teamwork.py slot acquire --agent developer-3 --provider deepseek --task T-0012
|
|
28
|
+
teamwork.py slot renew --agent developer-3 # every ~60 min on long work
|
|
29
|
+
teamwork.py slot release --agent developer-3
|
|
30
|
+
teamwork.py slot list # used / cap / free per provider
|
|
31
|
+
teamwork.py slot reap # expire dead leases
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
At the cap, `slot acquire` fails with exit 3 instead of blocking. The lane then
|
|
35
|
+
does work that needs no slot (read, plan, review a peer's output), fans out on
|
|
36
|
+
another provider, or waits for a lane to release - it never stalls the team.
|
|
37
|
+
|
|
38
|
+
### Plan the parallelism
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
teamwork.py parallel
|
|
42
|
+
# - focused reasoning lanes (ollama-cloud): 7 free
|
|
43
|
+
# - bulk fanout lanes (deepseek): 2496 free
|
|
44
|
+
# - start up to 7 new lane(s) now (ready tasks: 12)
|
|
45
|
+
# - 3 lane(s) already hold a slot: hand the next task to a running lane first
|
|
46
|
+
# - independent sub-tasks only: one writer per file
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The CEO uses this before every dispatch round: fill every free slot with
|
|
50
|
+
independent ready work, and scale `developer-N` / `tester-N` / `designer-N`
|
|
51
|
+
instances to the available capacity rather than to a fixed number.
|
|
52
|
+
|
|
53
|
+
### Work-in-progress, not lane count, is the throughput
|
|
54
|
+
|
|
55
|
+
A lane that holds one task and waits for its review is idle capacity. The engine
|
|
56
|
+
therefore schedules on **capacity**, not on idleness:
|
|
57
|
+
|
|
58
|
+
| Concept | Default | Where |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `LANE_WIP` - units one lane may hold (`doing` + `selfcheck`) | 2 | `engine.LANE_WIP` |
|
|
61
|
+
| Reviewer claims per lane | 1 | `review --claim` lease |
|
|
62
|
+
| Provider capacity | `Settings.json` (`ollama-cloud` 64, `deepseek` 2500) | `parallel`, `pulse` |
|
|
63
|
+
|
|
64
|
+
`task next <lane> --capacity N` claims N executable tasks at once; `pulse
|
|
65
|
+
--commit` tops every lane back up to its limit and refuses to plan more work than
|
|
66
|
+
there are free provider slots, printing the shortfall. A claim that is still live
|
|
67
|
+
blocks its lane; an expired claim is open for take-over, which is exactly what the
|
|
68
|
+
next pulse hands out.
|
|
69
|
+
|
|
70
|
+
### Stream the dependencies
|
|
71
|
+
|
|
72
|
+
`deps: role:T-id` waits for `done` and is the slowest possible edge. Two earlier
|
|
73
|
+
release points exist and should be used for every contract-shaped dependency:
|
|
74
|
+
|
|
75
|
+
| Dep form | Releases when | Use it for |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `role:T-id@started` | the owner has picked the task up | shadow work, fixtures, environment setup |
|
|
78
|
+
| `role:T-id@review` | the work is submitted for review | testing and docs against a frozen interface |
|
|
79
|
+
| `role:T-id` (default) | the task is `done` and merged | anything that needs the merged artifact |
|
|
80
|
+
|
|
81
|
+
Using `@review` on every interface dependency is what lets the tester, the writer
|
|
82
|
+
and the next developer start in the same hour rather than after a full review
|
|
83
|
+
cycle.
|
|
84
|
+
|
|
85
|
+
### Reuse before you recompute
|
|
86
|
+
|
|
87
|
+
- Reuse a **running lane** before spawning a new one - the teammate already holds
|
|
88
|
+
its memory, role and context.
|
|
89
|
+
- Reuse **evidence**: if a verification already passed on the same revision, cite
|
|
90
|
+
it (`BUILD ECONOMY`) instead of re-running.
|
|
91
|
+
- Reuse **research and artifacts**: read global memory, long-term memory and
|
|
92
|
+
`docs/Team/` before producing anything new; update in place, never duplicate.
|
|
93
|
+
- Reuse **build/test caches**; never rebuild from scratch for a clean slate.
|
|
94
|
+
- Reuse **the same artifact across lanes**: a frozen interface, fixture or script
|
|
95
|
+
is shared, not re-created per task.
|
|
96
|
+
- Deduplicate before dispatch: `teamwork.py audit` flags near-identical tasks.
|
|
97
|
+
|
|
98
|
+
### Parallelism rules (non-negotiable)
|
|
99
|
+
|
|
100
|
+
- One writer per file/worktree. Concurrency never means two agents editing the
|
|
101
|
+
same file.
|
|
102
|
+
- Only independent tasks run together; dependent tasks queue on their `deps`.
|
|
103
|
+
- The Reviewer, the Project Manager and the CEO are lanes too - keep them fed.
|
|
104
|
+
- **Review concurrency is the number of lanes, not the depth of the queue.**
|
|
105
|
+
`pulse --commit` fans unclaimed deliverables out one per idle Reviewer lane and
|
|
106
|
+
records a `review.claim` lease (`SlotTtlMinutes`, default 90 min) on each: the
|
|
107
|
+
holder counts as busy, another lane is refused while the lease is live, a verdict
|
|
108
|
+
or `--release` clears it, and an expired lease is open for take-over. So staff at
|
|
109
|
+
least `reviewer-1` and `reviewer-2`, and never stack the backlog on one lane.
|
|
110
|
+
- Never exceed a provider cap to "go faster": the extra lanes fail, and the
|
|
111
|
+
failure costs more than the parallelism gains.
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
## Per-agent model configuration
|
|
115
|
+
|
|
116
|
+
The skill does **not** ship a model and does not call an LLM API itself. Each
|
|
117
|
+
agent runs through the host's own API, so the model is a property of the *agent*,
|
|
118
|
+
not of the project, and every lane can pick one independently:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
teamwork.py model set reviewer --provider anthropic --model <strong> # role default
|
|
122
|
+
teamwork.py model set developer-1 --provider deepseek --model <cheap> # instance override
|
|
123
|
+
teamwork.py model get developer-1
|
|
124
|
+
teamwork.py model list
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- An **instance** setting wins over the **role** default; an unset agent uses the
|
|
128
|
+
host's own default and records `unset`.
|
|
129
|
+
- Give the reasoning-heavy lanes the stronger model (Reviewer, Architect,
|
|
130
|
+
Security Auditor) and the mechanical ones a cheaper or faster one (bulk edits,
|
|
131
|
+
formatting, link checks). Cost and latency are a per-lane choice, not a global one.
|
|
132
|
+
- A model change is a recorded act (`Settings.json` + the ledger); the CEO sets the
|
|
133
|
+
lanes at intake, and an agent never changes another agent's model.
|
|
134
|
+
- Model choice never changes the protocol: the evidence gates, the two-stage
|
|
135
|
+
review and the ledger hold whatever model produced the work.
|
|
136
|
+
|
|
137
|
+
### Automatic cost-aware routing
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
teamwork.py model auto # dry run: the plan, per lane
|
|
141
|
+
teamwork.py model auto --apply # write it into Settings.json
|
|
142
|
+
teamwork.py model auto --json
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`model auto` reads the *runtime environment* - which agent host is running (Pi,
|
|
146
|
+
Claude Code, opencode, Codex, Cursor, Gemini CLI) and which model that host already
|
|
147
|
+
exposes - and routes **the strongest available model to the lanes where a mistake
|
|
148
|
+
is expensive** (Reviewer, Architect, Security Auditor, CEO, CTO) and **the economy
|
|
149
|
+
model to the mechanical lanes** (developers, testers, writers, formatting, link
|
|
150
|
+
checks). Quality where it compounds, cheapness where it does not.
|
|
151
|
+
|
|
152
|
+
- It never invents a model id: `TEAMWORK_MODEL_STRONG` (or the host's own
|
|
153
|
+
`ANTHROPIC_MODEL` / `PI_MODEL` / `OPENCODE_MODEL` / ...) supplies the strong tier,
|
|
154
|
+
`TEAMWORK_MODEL_ECONOMY` the cheap one, and a lane with neither is reported as
|
|
155
|
+
`unset` together with the variable to set.
|
|
156
|
+
- `--apply` is explicit: the plan is a dry run by default, and applying it is
|
|
157
|
+
recorded in the ledger.
|
|
158
|
+
- Re-run it when the host or the budget changes; it is idempotent.
|
|
159
|
+
- `TEAMWORK_AGENT_HOST=claude|pi|opencode|codex|cursor|gemini` overrides
|
|
160
|
+
detection when the markers are ambiguous (CI, wrapper scripts).
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Decisions, dissent and the tribunal
|
|
2
|
+
|
|
3
|
+
Reference for the /teamwork skill. Loaded on demand; `SKILL.md` keeps the
|
|
4
|
+
operating procedure.
|
|
5
|
+
|
|
6
|
+
Related: [Engineering](Engineering.md) | [Evidence](Evidence.md) | [Docs](Docs.md) | [State](State.md) | [Concurrency](Concurrency.md) | [Roles](Roles.md) | [Testing](Testing.md) | [Audit](Audit.md)
|
|
7
|
+
|
|
8
|
+
## Decision and dissent protocol
|
|
9
|
+
|
|
10
|
+
The team's decisions are independent and evidence-based, not consensus by
|
|
11
|
+
deference.
|
|
12
|
+
|
|
13
|
+
**Every agent decides independently.** A decision is only valid with an evidence
|
|
14
|
+
chain: claim, data/measurement (command, file, benchmark, revision, source+date),
|
|
15
|
+
reasoning from evidence to conclusion, rejected alternatives, the bet you are
|
|
16
|
+
making, and the test that would falsify it. "I think", "should be fine" and
|
|
17
|
+
"best practice" are not evidence. Prefer measuring over debating; when a
|
|
18
|
+
measurement is impossible, label the decision provisional.
|
|
19
|
+
|
|
20
|
+
**Dissent is mandatory, not optional.** An agent that finds a design or decision
|
|
21
|
+
unreasonable must challenge the owner with counter-evidence instead of silently
|
|
22
|
+
complying or working around it:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
python3 "$SKILL/scripts/teamwork.py" dispute open \
|
|
26
|
+
--by developer-1 --against architect --topic "sync DB calls in request path" \
|
|
27
|
+
--position "will not meet the p99 target" \
|
|
28
|
+
--evidence "bench: 12ms/query x8 = 96ms @abc123 > 50ms budget" --task T-0007
|
|
29
|
+
python3 "$SKILL/scripts/teamwork.py" dispute round D-0001 --by architect \
|
|
30
|
+
--message "pooling measured at 14ms total @def456"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**3-round cap, then the tribunal.** The two agents get at most three rounds. If
|
|
34
|
+
they still disagree, the dispute escalates to the **CEO + CTO + CFO tribunal**,
|
|
35
|
+
which discusses it and issues a final, binding ruling:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
python3 "$SKILL/scripts/teamwork.py" dispute escalate D-0001 --by developer-1
|
|
39
|
+
python3 "$SKILL/scripts/teamwork.py" dispute sign D-0001 --by ceo # and cto, cfo
|
|
40
|
+
python3 "$SKILL/scripts/teamwork.py" dispute resolve D-0001 --by ceo \
|
|
41
|
+
--decision "pool + 20ms timeout + load-test gate"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The tool enforces this: a 4th round is refused, an escalated dispute cannot be
|
|
45
|
+
resolved until all three tribunal members have signed, and `audit` flags any open
|
|
46
|
+
dispute at the round cap. The ruling is recorded in `docs/Team/Decisions.md` and
|
|
47
|
+
is final - the losing side implements it and says so in its report. A dispute
|
|
48
|
+
never blocks unrelated work; keep going on everything not contested.
|
|
49
|
+
|
|
50
|
+
## Parallel lanes
|
|
51
|
+
|
|
52
|
+
The team is a set of lanes, not a queue:
|
|
53
|
+
|
|
54
|
+
- **Lane 0 (blocking, short):** requirements -> acceptance criteria -> frozen
|
|
55
|
+
interfaces -> task graph. Everyone else starts the moment this lands.
|
|
56
|
+
- **Lane A (code):** developers implement against the contract; unit tests are
|
|
57
|
+
part of each change.
|
|
58
|
+
- **Lane B (verification):** testers build integration/E2E suites from the same
|
|
59
|
+
contract in parallel with implementation, then run and monitor them.
|
|
60
|
+
- **Lane C (design):** designers produce specs and copy from the contract, then
|
|
61
|
+
review the merged UI.
|
|
62
|
+
- **Lane D (research/ops/cost):** PM research, COO risk and process, CFO cost,
|
|
63
|
+
running continuously and feeding lanes A-C.
|
|
64
|
+
- **Lane E (docs):** produced from merged code, scheduled last, never a gate.
|
|
65
|
+
|
|
66
|
+
Rules: one writer per file/worktree; interfaces frozen before parallel writers
|
|
67
|
+
start; interface changes require a `Decisions.md` entry plus notification to
|
|
68
|
+
every dependent lane; a lane that finishes takes the next unblocked task instead
|
|
69
|
+
of waiting.
|
|
70
|
+
|
|
71
|
+
## Failure handling
|
|
72
|
+
|
|
73
|
+
- **Infrastructure failure** (spawn, tool, provider): stop the lane, record the
|
|
74
|
+
exact error, worktree state and partial diff, retry once cleanly, then report
|
|
75
|
+
to the CEO. Never silently switch execution mode.
|
|
76
|
+
- **Blocked on a dependency**: mark the task `blocked` with the exact unblock
|
|
77
|
+
action and owner, tell the Project Manager, and take other executable work.
|
|
78
|
+
- **Blocked on the user**: CEO asks one consolidated question; the lane keeps
|
|
79
|
+
working elsewhere meanwhile.
|
|
80
|
+
- **Contradictory evidence**: escalate to the CEO; record the resolution in
|
|
81
|
+
`Decisions.md` and global memory.
|
|
82
|
+
- **Repeated failure of the same task**: the CEO re-scopes, splits, or reassigns;
|
|
83
|
+
it is never marked done to make the board look green.
|
|
84
|
+
- **Red-line refusal**: expected and correct behaviour. Record it, escalate, and
|
|
85
|
+
continue with the rest of the plan.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Documentation standard
|
|
2
|
+
|
|
3
|
+
Reference for the /teamwork skill. Loaded on demand; `SKILL.md` keeps the
|
|
4
|
+
operating procedure.
|
|
5
|
+
|
|
6
|
+
Related: [Engineering](Engineering.md) | [Evidence](Evidence.md) | [Docs](Docs.md) | [State](State.md) | [Concurrency](Concurrency.md) | [Roles](Roles.md) | [Testing](Testing.md) | [Audit](Audit.md)
|
|
7
|
+
|
|
8
|
+
## Documentation standard (markdown, structured, linked)
|
|
9
|
+
|
|
10
|
+
Everything the team writes - memory, plans, designs, research, decisions, docs -
|
|
11
|
+
is **markdown**, structured for a human reader, and cross-linked both ways.
|
|
12
|
+
This is enforced: `teamwork.py links` fails on broken links, malformed URLs, bare
|
|
13
|
+
URLs and missing back-links, and `audit` includes link health.
|
|
14
|
+
|
|
15
|
+
### Structure
|
|
16
|
+
|
|
17
|
+
- One `# H1` per file; the title states what the document is.
|
|
18
|
+
- A one-line `Owner:` line naming the role that maintains it.
|
|
19
|
+
- A `Related:` line directly under the header with relative links to every
|
|
20
|
+
document it interacts with (see the link graph below).
|
|
21
|
+
- Numbered `##` sections in reading order; `###` only when it earns its depth.
|
|
22
|
+
- Prefer tables and short bullets over paragraphs. One idea per bullet.
|
|
23
|
+
- Mark placeholders as `<like this>` so unfinished sections are obvious.
|
|
24
|
+
|
|
25
|
+
### Be concise (hard)
|
|
26
|
+
|
|
27
|
+
Saved content is read by humans under time pressure. Every file must be short
|
|
28
|
+
enough to scan.
|
|
29
|
+
|
|
30
|
+
- Lead with the conclusion; put the detail under it, never before it.
|
|
31
|
+
- One fact per line. Prefer a table row or a bullet over a paragraph.
|
|
32
|
+
- Write the smallest text that is still unambiguous. Delete anything the reader
|
|
33
|
+
already knows, any restatement of the brief, and any sentence that only
|
|
34
|
+
announces what the next sentence does.
|
|
35
|
+
- No filler: no "as mentioned above", "it is important to note", "in order to",
|
|
36
|
+
"various", "several", "etc." Lists are exhaustive or they are not lists.
|
|
37
|
+
- Numbers over adjectives: "12ms p99", not "quite fast". `<command> -> <result>`,
|
|
38
|
+
not "we verified it".
|
|
39
|
+
- A memory entry is **one line**: the fact, plus a key. If it needs three
|
|
40
|
+
paragraphs, it belongs in a document, not in memory.
|
|
41
|
+
- Cap each section at roughly one screen. If it grows past that, split the
|
|
42
|
+
document or move detail to a linked file.
|
|
43
|
+
- Rewrite, do not append. Documents and memory entries are kept current, not
|
|
44
|
+
accumulated; stale text is deleted rather than left below new text.
|
|
45
|
+
|
|
46
|
+
### Links
|
|
47
|
+
|
|
48
|
+
- **External references always carry a direct, working link plus an access date**:
|
|
49
|
+
`- [title](https://full-url) - accessed YYYY-MM-DD`. Never cite a search page,
|
|
50
|
+
a bare domain, or "the docs" without a URL. A claim without a link is
|
|
51
|
+
`UNVERIFIED` and cannot justify a decision.
|
|
52
|
+
- **Internal references are relative markdown links** to the file
|
|
53
|
+
(`[PLAN](Plan.md)`), never absolute paths and never bare file names in prose.
|
|
54
|
+
- **Bidirectional**: if A links to B, B links back to A. Put the back-link in the
|
|
55
|
+
`Related:` line, which is why every shared document has one.
|
|
56
|
+
- Every decision cites the evidence and the documents it affects; every research
|
|
57
|
+
claim cites its source; every task result cites the artifact and the command.
|
|
58
|
+
|
|
59
|
+
### Link graph (committed docs, every edge bidirectional)
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
PROJECT ─ PLAN ─ BOARD ─ ARCHIVE
|
|
63
|
+
│ │ │ │
|
|
64
|
+
│ ├──────┴────────┴── RISKS ─ COSTS
|
|
65
|
+
│ │ │
|
|
66
|
+
├── ARCHITECTURE ─ DESIGN │
|
|
67
|
+
│ │ │
|
|
68
|
+
├── RESEARCH ─────────────────┘
|
|
69
|
+
└── DECISIONS (links to ARCHITECTURE, RESEARCH, RISKS, COSTS, ARCHIVE, PLAN)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`teamwork.py links` verifies it. `.pi/` memory files link to `TaskQueue.md`,
|
|
73
|
+
`Role.md`, `ShortTermMemory.md`, `LongTermMemory.md`, global memory and the committed docs
|
|
74
|
+
they inform.
|