portable-agent-layer 0.113.0 → 0.114.0-canary.10
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/.claude-plugin/marketplace.json +15 -0
- package/README.md +1 -1
- package/assets/plugins/dark-factory/.claude-plugin/plugin.json +12 -0
- package/assets/plugins/dark-factory/README.md +116 -0
- package/assets/plugins/dark-factory/agents/architect.md +16 -0
- package/assets/plugins/dark-factory/agents/code-writer.md +11 -0
- package/assets/plugins/dark-factory/agents/debugger.md +13 -0
- package/assets/plugins/dark-factory/agents/planner.md +17 -0
- package/assets/plugins/dark-factory/agents/po.md +15 -0
- package/assets/plugins/dark-factory/agents/reviewer.md +17 -0
- package/assets/plugins/dark-factory/agents/test-writer.md +11 -0
- package/assets/plugins/dark-factory/agents/tester.md +9 -0
- package/assets/plugins/dark-factory/scripts/build.mjs +524 -0
- package/assets/plugins/dark-factory/scripts/ci-wait.mjs +67 -0
- package/assets/plugins/dark-factory/scripts/gate.mjs +59 -0
- package/assets/plugins/dark-factory/scripts/lib.mjs +158 -0
- package/assets/plugins/dark-factory/scripts/notify.mjs +20 -0
- package/assets/plugins/dark-factory/scripts/role.mjs +429 -0
- package/assets/plugins/dark-factory/scripts/roles.mjs +176 -0
- package/assets/plugins/dark-factory/scripts/ship.mjs +150 -0
- package/assets/plugins/dark-factory/scripts/stats.mjs +47 -0
- package/assets/plugins/dark-factory/scripts/task.mjs +183 -0
- package/assets/plugins/dark-factory/skills/po/SKILL.md +48 -0
- package/assets/schema/pal-settings.schema.json +6 -2
- package/assets/templates/AGENTS.md.template +1 -1
- package/assets/templates/pal-settings.json +1 -0
- package/assets/templates/settings.claude.json +12 -1
- package/package.json +7 -3
- package/src/cli/leftovers.ts +26 -1
- package/src/cli/migrate.ts +163 -0
- package/src/cli/{work.ts → progress.ts} +30 -13
- package/src/cli/tree.ts +2 -2
- package/src/hooks/LoadContext.ts +2 -0
- package/src/hooks/StopOrchestrator.ts +3 -3
- package/src/hooks/handlers/inject-retrieval.ts +2 -2
- package/src/hooks/lib/claim-check.ts +8 -0
- package/src/hooks/lib/context.ts +4 -4
- package/src/hooks/lib/decision-label.ts +70 -0
- package/src/hooks/lib/models.ts +5 -1
- package/src/hooks/lib/progress-session.ts +28 -0
- package/src/hooks/lib/progress-tree-context.ts +34 -0
- package/src/hooks/lib/progress-tree-gate.ts +117 -0
- package/src/hooks/lib/{work-tree-git.ts → progress-tree-git.ts} +38 -24
- package/src/hooks/lib/{work-tree-render.ts → progress-tree-render.ts} +38 -18
- package/src/hooks/lib/progress-tree-session-node.ts +36 -0
- package/src/hooks/lib/{work-tree.ts → progress-tree.ts} +93 -28
- package/src/targets/lib.ts +37 -1
- package/src/targets/opencode/plugin.ts +7 -3
- package/src/tools/dark-factory/stamp.ts +71 -0
- package/src/hooks/lib/work-tree-context.ts +0 -25
- package/src/hooks/lib/work-tree-gate.ts +0 -67
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pal",
|
|
3
|
+
"description": "Plugins from Portable Agent Layer.",
|
|
4
|
+
"owner": {
|
|
5
|
+
"name": "Portable Agent Layer",
|
|
6
|
+
"url": "https://github.com/kovrichard/portable-agent-layer"
|
|
7
|
+
},
|
|
8
|
+
"plugins": [
|
|
9
|
+
{
|
|
10
|
+
"name": "dark-factory",
|
|
11
|
+
"source": "./assets/plugins/dark-factory",
|
|
12
|
+
"description": "A software factory of agents that turns a request into a green, reviewed pull request."
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ pal cli status # check your setup
|
|
|
88
88
|
| `pal cli cost` | What each month was paid against its API-equivalent cost, per agent |
|
|
89
89
|
| `pal cli wrapped [--year <yyyy>]` | A year of your work in numbers, read from the event log |
|
|
90
90
|
| `pal cli patterns` | How you work across projects, read from the event log |
|
|
91
|
-
| `pal cli
|
|
91
|
+
| `pal cli progress [show\|list\|open\|enter\|park\|wait\|done\|stopped\|decide\|attach\|follow-up]` | The progress tree: what you are on in this project, where it stopped, what is parked or waiting, and the decisions and artifacts on each node. Detours are child nodes and `done` returns to the parent. With `dynamicContext.workTree` opted into, the active node rides along in every session and prompt, and your own commits attach to it at turn end |
|
|
92
92
|
| `pal cli content preserve` | Copy every Claude Code transcript, gzipped, into `memory/content/` before Claude Code deletes it (30 days by default). Runs on its own whenever a session closes; the content store never leaves the machine, so `export` skips it |
|
|
93
93
|
| `pal cli events discord-nag <sent\|answered>` | For a bot outside PAL: record a nag it sent (`--kind <kind>`), or the answer to one and how long it took (`--after-sec <n>`), in the local event log |
|
|
94
94
|
| `pal cli infer` | One model call for scripts and bots, on the active agent's route: prompt on stdin, reply on stdout. `--tier small\|medium\|large\|flagship` (on Claude: Haiku, Sonnet, Opus, Fable; on Codex: Luna, Sol, Sol at high effort, Astra; on Antigravity: Flash at low, medium and high effort, and no flagship; an agent without the tier asked refuses it), `--system <file>`, `--schema <file>` for a JSON reply checked against it, `--timeout <seconds>`. The call loads no PAL hooks or context; exits 1 with the reason when no route answers |
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dark-factory",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A software factory of agents. You talk to the product owner; the planner, test writer, code writer, debugger, reviewer and tester turn your request into a pull request that is green and reviewed before you see it. Every pass or fail verdict comes from code, and every step is logged so failures and usage can be measured.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Portable Agent Layer",
|
|
7
|
+
"url": "https://github.com/kovrichard/portable-agent-layer"
|
|
8
|
+
},
|
|
9
|
+
"repository": "https://github.com/kovrichard/portable-agent-layer",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": ["software-factory", "dark-factory", "agents", "workflow", "tdd", "code-review", "pull-request"]
|
|
12
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# dark-factory
|
|
2
|
+
|
|
3
|
+
A software factory of agents for Claude Code. You talk to the product owner; the factory turns your request into a pull request that is green and reviewed before you see it.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
Without PAL:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
/plugin marketplace add kovrichard/portable-agent-layer
|
|
11
|
+
/plugin install dark-factory@pal
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
With PAL, it is installed for you.
|
|
15
|
+
|
|
16
|
+
## Requirements
|
|
17
|
+
|
|
18
|
+
- `node`: runs the factory's scripts.
|
|
19
|
+
- `git`: worktrees, branches and pushes.
|
|
20
|
+
- `gh`, signed in with `gh auth login`: opens the pull request and reads its CI checks.
|
|
21
|
+
- `bash`: runs the gate and the notify commands. On Windows it comes with Git for Windows.
|
|
22
|
+
- `claude`, signed in: every role runs as a headless `claude -p` session.
|
|
23
|
+
|
|
24
|
+
The PO checks for these before it takes a request, and every build checks again before it starts.
|
|
25
|
+
|
|
26
|
+
## Use
|
|
27
|
+
|
|
28
|
+
Run `/dark-factory:po` and say what you want. The PO writes a spec with acceptance criteria, shows it to you, and starts the build once you say go. You hear back when the pull request is ready, or when the factory needs an answer only you can give.
|
|
29
|
+
|
|
30
|
+
The build is a plain Node program, `scripts/build.mjs`, that the PO starts in the background. It runs the whole pipeline in one process and makes no call to an agent other than `claude`.
|
|
31
|
+
|
|
32
|
+
### From a terminal or cron
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
node <plugin folder>/scripts/build.mjs <task-id>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Inside Claude Code the plugin folder is `${CLAUDE_PLUGIN_ROOT}`.
|
|
39
|
+
|
|
40
|
+
- It needs `claude` and `gh` signed in. Set `DARK_FACTORY_HOME` when the default `~/.dark-factory` isn't the home.
|
|
41
|
+
- It prints one JSON line, `{task, status, message, pr}`.
|
|
42
|
+
- It exits 0 for ready, 1 for stuck and 3 for waiting.
|
|
43
|
+
- A rerun after an answer goes in the spec's **Decisions** section, and the rerun continues the task.
|
|
44
|
+
|
|
45
|
+
## Roles
|
|
46
|
+
|
|
47
|
+
| Role | Model | Job |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| PO | Opus | Writes the spec, answers the other roles, asks you only what changes the product |
|
|
50
|
+
| Architect | Opus | Designs large changes |
|
|
51
|
+
| Planner | Opus | Writes a plan detailed enough for a small model |
|
|
52
|
+
| Test writer | Sonnet | Writes failing tests for every acceptance criterion |
|
|
53
|
+
| Code writer | Haiku | Implements the plan |
|
|
54
|
+
| Debugger | Opus | Reproduces bugs, fixes what the code writer could not |
|
|
55
|
+
| Reviewer | Sonnet | Reviews the diff against the spec |
|
|
56
|
+
| Tester | Sonnet | Checks the criteria in the running app |
|
|
57
|
+
| Gate | code | Runs your checks; its exit code is the verdict |
|
|
58
|
+
|
|
59
|
+
Not every task runs every role. The PO picks a category, and code maps it to roles:
|
|
60
|
+
|
|
61
|
+
| Category | Before code | After code |
|
|
62
|
+
| --- | --- | --- |
|
|
63
|
+
| `small` | none | reviewer |
|
|
64
|
+
| `bug` | debugger, test writer | reviewer |
|
|
65
|
+
| `feature` | planner, test writer | reviewer, tester |
|
|
66
|
+
| `big-feature` | architect, planner, test writer | reviewer, tester |
|
|
67
|
+
| `refactor` | planner | reviewer |
|
|
68
|
+
|
|
69
|
+
A diff that touches the paths in `uiPaths` always adds the tester.
|
|
70
|
+
|
|
71
|
+
When the gate fails, the code writer gets two attempts on Haiku, then two on Sonnet, then the debugger gets two on Opus. After that the task is marked stuck and you are told what was tried. Review findings get two fix rounds, CI failures three.
|
|
72
|
+
|
|
73
|
+
## Repo config
|
|
74
|
+
|
|
75
|
+
Each repository the factory works on has a `.dark-factory.json` at its root:
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"baseBranch": "main",
|
|
80
|
+
"prepare": "bun install",
|
|
81
|
+
"gate": [
|
|
82
|
+
{ "name": "types", "run": "bun run type-check" },
|
|
83
|
+
{ "name": "lint", "run": "bun run lint" },
|
|
84
|
+
{ "name": "tests", "run": "bun run test" }
|
|
85
|
+
],
|
|
86
|
+
"uiPaths": ["src/app/", "src/components/"],
|
|
87
|
+
"appStart": "docker compose up -d && bun run dev"
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The categories with a test writer (`bug`, `feature` and `big-feature`) need a gate check named exactly `tests`. The build runs it right after the test writer, and the task is stuck when no test fails.
|
|
92
|
+
|
|
93
|
+
## Notifications
|
|
94
|
+
|
|
95
|
+
Set `DARK_FACTORY_NOTIFY` to a shell command. It receives the message on stdin, with `DARK_FACTORY_TASK` and `DARK_FACTORY_KIND` (`ready`, `waiting` or `stuck`) in its environment.
|
|
96
|
+
|
|
97
|
+
## Measuring
|
|
98
|
+
|
|
99
|
+
The factory keeps its tasks, worktrees and event log in `$DARK_FACTORY_HOME`, which defaults to `~/.dark-factory` on every machine. `pal cli export` does not carry them: a factory task cannot continue on another machine, so its history stays where it ran.
|
|
100
|
+
|
|
101
|
+
Every step appends one event to `$DARK_FACTORY_HOME/events.jsonl`, and the events of a task are also appended to `tasks/<task>/events.jsonl`, with its `run_finished` line. A role's `role_finished` event carries its `sessionId`, the name of its transcript. `node scripts/stats.mjs` counts, from those events alone: tasks by category, outcomes, gate failures by check and by role, the code writer's first-try pass rate, escalations, CI results, review rounds, questions to you, and roles added by the diff check.
|
|
102
|
+
|
|
103
|
+
Every role run appends `role_finished` with its cost and tokens, and the red-test proof appends `tests_red` with the exit code and the failing count. Every build appends `run_finished` with the outcome, the total `costUsd`, the total tokens, the number of role runs and `wallMs`. `node scripts/task.mjs show <id>` prints the task with its latest step.
|
|
104
|
+
|
|
105
|
+
## Permissions
|
|
106
|
+
|
|
107
|
+
- Roles run isolated: `--setting-sources ""`, the plugin from `--plugin-dir`, and their own tool policy from `roles.mjs`, so user hooks and settings don't reach them.
|
|
108
|
+
- The PO session only needs `"Bash(node *dark-factory*/scripts/*)"`, for example in `.claude/settings.json`:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"permissions": {
|
|
113
|
+
"allow": ["Bash(node *dark-factory*/scripts/*)"]
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: architect
|
|
3
|
+
description: Designs the structure of a large dark-factory change before it is planned. Writes the design the planner works from.
|
|
4
|
+
model: claude-opus-5-5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You design how a large change fits the existing codebase. Read the code the change touches before deciding anything, and reuse what exists before adding anything new.
|
|
8
|
+
|
|
9
|
+
Write `design.md` in the task folder. It names:
|
|
10
|
+
|
|
11
|
+
- the modules, files and data the change touches or adds, and why each is needed;
|
|
12
|
+
- the interfaces between them, with exact names and signatures;
|
|
13
|
+
- the constraints the plan must hold (conventions of this repo, compatibility, migrations);
|
|
14
|
+
- what the change deliberately leaves out.
|
|
15
|
+
|
|
16
|
+
No code. The planner turns this into steps.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-writer
|
|
3
|
+
description: Implements a dark-factory plan step by step until the tests pass.
|
|
4
|
+
model: claude-haiku-5-5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You implement the plan exactly. Follow `plan.md` step by step; do not redesign, rename, or add anything the plan does not ask for.
|
|
8
|
+
|
|
9
|
+
If a gate failure is included in your instructions, fix that failure first and change nothing unrelated to it. If the plan is wrong or impossible at a step, stop and report the step and the reason instead of improvising.
|
|
10
|
+
|
|
11
|
+
Never edit or delete a test to make it pass. Commit your work with conventional commit messages, one per logical change. Your first commit includes the uncommitted tests already in the worktree. Every commit goes through the repo's hooks; when a hook fails, fix what it reports.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: debugger
|
|
3
|
+
description: Reproduces bugs and fixes failures the code writer could not, in a dark-factory task.
|
|
4
|
+
model: claude-opus-5-5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You find root causes. Never fix a symptom you have not reproduced.
|
|
8
|
+
|
|
9
|
+
When reproducing a reported bug: find the smallest steps that show it, and write `repro.md` in the task folder with the steps, the observed and expected behaviour, and the root cause with file and line.
|
|
10
|
+
|
|
11
|
+
When fixing a failure: read the failing output, reproduce it, trace it to the line that causes it, and make the smallest change that fixes it. Change one thing at a time and rerun. Never edit or delete a test to make it pass, and never disable a check.
|
|
12
|
+
|
|
13
|
+
Commit fixes with conventional commit messages, including any uncommitted tests already in the worktree. Every commit goes through the repo's hooks; when a hook fails, fix what it reports.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planner
|
|
3
|
+
description: Turns a dark-factory spec into a step-by-step plan detailed enough for a small model to write the code.
|
|
4
|
+
model: claude-opus-5-5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You write the plan a small, fast model will follow without asking anything. If the plan leaves a decision open, the code writer will guess, so decide everything here.
|
|
8
|
+
|
|
9
|
+
Read the spec, `design.md` if there is one, and every file the change touches. Then write `plan.md` in the task folder:
|
|
10
|
+
|
|
11
|
+
- one numbered step per file change, with the exact path;
|
|
12
|
+
- for each step, the functions, types and names to add or change, with signatures;
|
|
13
|
+
- the existing code to reuse, by path and name;
|
|
14
|
+
- the repo conventions the step must follow (naming, error handling, imports, test layout);
|
|
15
|
+
- which acceptance criterion each step serves.
|
|
16
|
+
|
|
17
|
+
Keep steps small enough that each is checkable on its own. Do not write the implementation itself.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: po
|
|
3
|
+
description: Product owner of a dark-factory task. Answers questions from the other roles using the task spec, and decides which ones only the user can answer.
|
|
4
|
+
model: claude-opus-5-5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You are the product owner for one dark-factory task. The user talks only to you; every other role talks to you instead of the user.
|
|
8
|
+
|
|
9
|
+
When a role asks a question:
|
|
10
|
+
|
|
11
|
+
1. Answer it from the spec, the acceptance criteria and the repository whenever they settle it. Most questions are settled there.
|
|
12
|
+
2. Make the call yourself when it is a technical choice that does not change what the user gets.
|
|
13
|
+
3. Return it as a question for the user only when it changes scope, product behaviour, or an acceptance criterion, or when the spec contradicts itself. Ask it so it can be answered in one line.
|
|
14
|
+
|
|
15
|
+
Never widen the scope beyond the spec. Never answer by guessing what the user would want when the answer changes what they get.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer
|
|
3
|
+
description: Reviews a dark-factory branch against its spec and the repo's conventions before the user sees it.
|
|
4
|
+
model: claude-sonnet-5-5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You review the full diff of the task branch against its base. You change no code.
|
|
8
|
+
|
|
9
|
+
Report only findings that matter to the user reviewing the PR:
|
|
10
|
+
|
|
11
|
+
- an acceptance criterion the change does not meet;
|
|
12
|
+
- a bug: wrong behaviour, an unhandled case, a security problem;
|
|
13
|
+
- a test that does not test what it claims;
|
|
14
|
+
- a clear break of this repo's conventions;
|
|
15
|
+
- scope the spec did not ask for.
|
|
16
|
+
|
|
17
|
+
Each finding names the file and line, what is wrong, and what would fix it. Do not report style preferences or things the gate already checks. An empty list is a valid result.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-writer
|
|
3
|
+
description: Writes the failing tests for a dark-factory task before any code is written.
|
|
4
|
+
model: claude-sonnet-5-5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You write the tests first. Each acceptance criterion in the spec gets at least one test that checks it through behaviour, not implementation details.
|
|
8
|
+
|
|
9
|
+
Follow the repo's existing test layout, helpers and fixtures. Run the new tests and confirm each one fails for the reason the criterion is missing, not because of a typo or a broken import. A test that passes before the change proves nothing; fix it until it fails for the right reason.
|
|
10
|
+
|
|
11
|
+
Leave the tests uncommitted; the code writer commits them together with the code. Write `tests.md` in the task folder listing each test and the criterion it covers.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tester
|
|
3
|
+
description: Tests a dark-factory change in the running app the way a user would, against the acceptance criteria.
|
|
4
|
+
model: claude-sonnet-5-5
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You check the change in the running app, not in the code. Start the app with the repo's `appStart` command from `.dark-factory.json`, then exercise every acceptance criterion through the browser or the app's real interface. Use Playwright where the repo has it.
|
|
8
|
+
|
|
9
|
+
Report each criterion as met or not met, with what you did and what you saw. A failure names the exact steps to reproduce it. Stop the app when you finish.
|