unitbob 0.7.12 → 0.7.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -80
- package/dist/cli.js +3 -1
- package/dist/verbs/fixPrepare.js +21 -9
- package/dist/wire.js +9 -0
- package/package.json +1 -1
- package/plugin/codex/agents/suite-repair-worker.toml +1 -1
package/README.md
CHANGED
|
@@ -1,134 +1,142 @@
|
|
|
1
1
|
# Unitbob
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Unitbob draws a map of what your app does for people — signing in, paying,
|
|
4
|
+
sending messages — and puts a lamp on each part. Behind every lamp is an
|
|
5
|
+
automatic check. Green means that part still works. Red means something you
|
|
6
|
+
changed broke it.
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
You do not write the checks. Your coding assistant — Claude Code or Codex —
|
|
9
|
+
does, and Unitbob keeps them honest. Your code stays on your computer; only
|
|
10
|
+
the checks and their results go to Unitbob.
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
Node 18
|
|
12
|
+
Works with apps written in Ruby on Rails, JavaScript/TypeScript and Python.
|
|
13
|
+
You need Node 18 or newer and Python 3.10 or newer installed.
|
|
12
14
|
|
|
13
15
|
---
|
|
14
16
|
|
|
15
17
|
## Install (once)
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
Tell your assistant:
|
|
20
|
+
|
|
18
21
|
```
|
|
19
22
|
Add the Unitbob plugin marketplace: sergeygershun/unitbob-connector
|
|
20
23
|
Install the unitbob plugin
|
|
21
24
|
```
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
Or, if you prefer the terminal — Claude Code:
|
|
27
|
+
|
|
24
28
|
```
|
|
25
29
|
claude plugin marketplace add sergeygershun/unitbob-connector
|
|
26
30
|
claude plugin install unitbob@unitbob
|
|
27
31
|
```
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
Codex:
|
|
34
|
+
|
|
30
35
|
```
|
|
31
36
|
codex plugin marketplace add sergeygershun/unitbob-connector
|
|
32
37
|
codex plugin add unitbob@unitbob
|
|
33
|
-
npx -y unitbob@0.
|
|
38
|
+
npx -y unitbob@0.7.14 codex-install
|
|
34
39
|
```
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
hosts.
|
|
41
|
+
Then start a new chat. A chat opened before the install does not know about
|
|
42
|
+
Unitbob yet. Everything below works the same in Claude Code and Codex.
|
|
39
43
|
|
|
40
|
-
Codex
|
|
41
|
-
|
|
42
|
-
than enforced separately for each named agent. No Codex version is currently
|
|
43
|
-
qualified by Unitbob for a native per-agent ceiling. Before the first bounded
|
|
44
|
-
role, Unitbob therefore asks whether to continue this invocation without that
|
|
45
|
-
mechanical ceiling; approval is never persisted. The definitions keep the native
|
|
46
|
-
budget values so a future Codex release can be qualified without introducing a
|
|
47
|
-
Unitbob supervisor.
|
|
44
|
+
On Codex, the assistant may ask once whether it can continue without a spending
|
|
45
|
+
limit for its helpers. Answer yes; Codex cannot enforce that limit yet.
|
|
48
46
|
|
|
49
47
|
---
|
|
50
48
|
|
|
51
|
-
##
|
|
49
|
+
## Protect what your app already does
|
|
52
50
|
|
|
53
|
-
Just
|
|
51
|
+
Just say it in the chat. Nothing to memorise, no command to get right.
|
|
54
52
|
|
|
55
53
|
| Step | Say this |
|
|
56
54
|
|------|----------|
|
|
57
|
-
| 1.
|
|
58
|
-
| 2.
|
|
59
|
-
| 3.
|
|
60
|
-
| 4.
|
|
55
|
+
| 1. Draw the map | `Build my Unitbob map` |
|
|
56
|
+
| 2. Write the checks | `Generate the guardrail tests` |
|
|
57
|
+
| 3. Look at the map | `Open my Unitbob map` |
|
|
58
|
+
| 4. Fix a red lamp | `Fix guardrail <id>` — the id is written on the lamp |
|
|
61
59
|
|
|
62
|
-
Step 2
|
|
63
|
-
|
|
60
|
+
Step 2 also runs the checks, so the lamps light up right away. Later, whenever
|
|
61
|
+
you want to know whether your latest changes broke anything, say `Run the
|
|
62
|
+
checks`.
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
tests were saved but before they ran.
|
|
64
|
+
Your project connects itself to Unitbob the first time. There is nothing to
|
|
65
|
+
set up by hand.
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Build something new
|
|
70
|
+
|
|
71
|
+
The steps above protect what your app does today. When you want to add
|
|
72
|
+
something new, Unitbob can protect the new part too — before it exists. Then
|
|
73
|
+
"done" is not a feeling; it is the checks turning green.
|
|
74
|
+
|
|
75
|
+
Do steps 1 and 2 above first. Then, in the chat, in this order:
|
|
76
|
+
|
|
77
|
+
| Step | Say this | What happens |
|
|
78
|
+
|------|----------|--------------|
|
|
79
|
+
| 1. Name it | `I want to add <feature>` | Unitbob writes down what you want and which parts of the map it may touch. You get a link to the feature's page. |
|
|
80
|
+
| 2. Talk it through | `Let's talk through <feature>` | The assistant asks a few numbered questions about how the feature should behave — in plain words, with options and a recommendation. Answer with a letter, a word, or `do as you recommend`. Then it shows you the list of things that will be true when the feature is done and asks: is this it? Say `yes`. |
|
|
81
|
+
| 3. Write the checks | `Write the checks for <feature>` | Each item from that list becomes a check. They are all red now — on purpose, the feature is not built yet. |
|
|
82
|
+
| 4. Build it | `Build <feature>` | Ordinary work in the same chat. Say `Run the checks` at any time to see how many of the feature's checks already pass, and whether anything else broke. The moment they all pass, a second assistant reads them over on its own and you get the link to the feature's page. |
|
|
83
|
+
| 5. Wrap up | `I'm done with <feature>` | Only if step 4 did not end on that link: the checks run once more, the second assistant reads them over, and you get the link. |
|
|
84
|
+
| 6. Finish | Press **Finish this feature** on that page | Only you can press it, and only when everything is green. The feature gets its own lamp on the map, already green. |
|
|
85
|
+
|
|
86
|
+
Good to know:
|
|
87
|
+
|
|
88
|
+
- **If the button is grey, the page says why** — a check of the feature still
|
|
89
|
+
fails, the checks have not been read over yet, or something you said must
|
|
90
|
+
keep working is red.
|
|
91
|
+
- **A red lamp you expected is fine.** If in step 2 you said a part would
|
|
92
|
+
change, its row on the feature page is amber, not red, with a button
|
|
93
|
+
`Accept the new behaviour`. Press it and it is green again. A red lamp you
|
|
94
|
+
did not expect is shown too, with the usual `Fix this`.
|
|
95
|
+
- **The checks say exactly what you agreed to in step 2.** Nobody can quietly
|
|
96
|
+
bend them to fit the code. If you change your mind about the feature, say
|
|
97
|
+
`Let's talk through <feature>` again and the checks are rewritten.
|
|
98
|
+
- **Work in your project's main folder.** Unitbob keeps the checks in a folder
|
|
99
|
+
called `.unitbob` next to your code. A copy of the project in another folder
|
|
100
|
+
does not have it.
|
|
101
|
+
- **After Finish, nothing more to do.** From now on the feature's checks run
|
|
102
|
+
with all the others.
|
|
73
103
|
|
|
74
104
|
### If the assistant says it cannot find the Unitbob instructions
|
|
75
105
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
clean fix. If that is inconvenient, the instructions are ordinary files on disk
|
|
79
|
-
and the assistant can read them directly — tell it:
|
|
106
|
+
The chat was started before the plugin was installed. Start a new chat. If you
|
|
107
|
+
would rather not, tell the assistant:
|
|
80
108
|
|
|
81
109
|
```
|
|
82
110
|
Read ~/.claude/plugins/cache/unitbob/unitbob/<version>/skills/unitbob/SKILL.md
|
|
83
111
|
and follow the workflow it names for this job.
|
|
84
112
|
```
|
|
85
113
|
|
|
86
|
-
`<version>` is
|
|
87
|
-
workflow files sit next to it under `workflows/`, one per job, and each is
|
|
88
|
-
self-contained — that is what they are designed for.
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
## How to read it
|
|
93
|
-
|
|
94
|
-
- **Green lamp** — the behavior works.
|
|
95
|
-
- **Red lamp** — something the structure relied on broke. Copy its `id` and run
|
|
96
|
-
step 3.
|
|
97
|
-
- The project links itself by folder name — nothing to set up by hand.
|
|
114
|
+
`<version>` is the number that `claude plugin list` shows.
|
|
98
115
|
|
|
99
116
|
---
|
|
100
117
|
|
|
101
|
-
## If your
|
|
118
|
+
## If your app only runs inside Docker
|
|
102
119
|
|
|
103
|
-
Some projects keep the code on
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
there:
|
|
120
|
+
Some projects keep the code on your computer but run it inside a Docker
|
|
121
|
+
container. Tell Unitbob the container's name in the file `.unitbob.json` in
|
|
122
|
+
your project folder:
|
|
107
123
|
|
|
108
124
|
```json
|
|
109
125
|
{ "server": "…", "repo_id": 3, "token": "…",
|
|
110
126
|
"exec": { "docker": { "container": "myapp-web-1" } } }
|
|
111
127
|
```
|
|
112
128
|
|
|
113
|
-
|
|
114
|
-
the container
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
- **On a Linux host, files the container writes belong to `root`.** Unitbob does
|
|
128
|
-
not map users: guessing there breaks images that installed their packages as a
|
|
129
|
-
user of their own.
|
|
130
|
-
- **Only a container that is already running.** A project whose tests go through
|
|
131
|
-
`docker compose run --rm` is not supported yet.
|
|
132
|
-
- **Review at a fixed revision is not supported with a container.** It works in
|
|
133
|
-
a git worktree under the system's temporary directory, which is outside the
|
|
134
|
-
mount. Ordinary review works in the project itself and is unaffected.
|
|
129
|
+
Keep the other three values as they are; Unitbob wrote them. Now the checks
|
|
130
|
+
run inside the container. Without that line everything runs on your computer,
|
|
131
|
+
as before.
|
|
132
|
+
|
|
133
|
+
This works only when the project folder is shared with the container — which
|
|
134
|
+
it already is if editing a file on your computer changes the running app. If
|
|
135
|
+
it is not, Unitbob tells you and stops.
|
|
136
|
+
|
|
137
|
+
A few things Unitbob does not do in a container yet:
|
|
138
|
+
|
|
139
|
+
- The container has to be running already; Unitbob does not start it.
|
|
140
|
+
- On Linux, files written from inside the container belong to `root`.
|
|
141
|
+
- If a check takes too long and is stopped, the container may keep running it
|
|
142
|
+
in the background for a while.
|
package/dist/cli.js
CHANGED
|
@@ -73,7 +73,9 @@ Verbs:
|
|
|
73
73
|
Internal: run the suite you just wrote, before publishing it, with the same runner
|
|
74
74
|
that will run it afterwards. No argument runs every branch the build asked for;
|
|
75
75
|
--feature runs one feature's checks alone, by their tag.
|
|
76
|
-
fix-prepare <id>
|
|
76
|
+
fix-prepare [<id>] Without an id: every red guard on both maps, with its suite digest and history — the
|
|
77
|
+
list a fix starts from. With an id: the per-capability repair packet for one
|
|
78
|
+
structural guard (spec 26).
|
|
77
79
|
contract-prompt <digest>|feature:<id> <test_id> [fix|accept]
|
|
78
80
|
Internal: fetch the fix/accept brief for one red check on either map — or, with
|
|
79
81
|
feature:<id>, the fix brief for a feature's own failing checks.
|
package/dist/verbs/fixPrepare.js
CHANGED
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
import { writeFixRequest } from "../files/fix.js";
|
|
2
2
|
import { Wire } from "../wire.js";
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
3
|
+
// Two forms, one verb.
|
|
4
|
+
//
|
|
5
|
+
// Without an id (spec 54-1): print the list a fix starts from — every red guard
|
|
6
|
+
// of both maps under the digest it is red on, with the line that says whether
|
|
7
|
+
// it ever passed on that suite. The server words it; the connector prints it
|
|
8
|
+
// as it is. Nothing is written: the list is read, the brief comes next from
|
|
9
|
+
// `contract-prompt` with the digest copied off this list.
|
|
10
|
+
//
|
|
11
|
+
// With an id (spec 26): fetch the per-capability repair packet and write the
|
|
12
|
+
// host's task to `.unitbob/fix/request.json`. No recipe fetch, no upload — the
|
|
13
|
+
// host reads its own source and the local spec file, then either fixes code
|
|
14
|
+
// (next `/unitbob check` shows the result) or accepts the change and
|
|
15
|
+
// republishes the suite. A 422 from the server (non-failed / stale / no suite)
|
|
16
|
+
// surfaces via WireError; nothing is written.
|
|
9
17
|
export async function fixPrepare(config, args = [], deps) {
|
|
10
|
-
const interfaceId = (args[0] ?? '').trim();
|
|
11
|
-
if (!interfaceId)
|
|
12
|
-
throw new Error('Usage: unitbob fix-prepare <interface_id>');
|
|
13
18
|
const d = {
|
|
19
|
+
getRedList: () => new Wire(config).getRedList(),
|
|
14
20
|
getFixPacket: (id) => new Wire(config).getFixPacket(id),
|
|
15
21
|
stdout: process.stdout,
|
|
16
22
|
...deps,
|
|
17
23
|
};
|
|
24
|
+
const interfaceId = (args[0] ?? '').trim();
|
|
25
|
+
if (!interfaceId) {
|
|
26
|
+
const list = await d.getRedList();
|
|
27
|
+
d.stdout.write(`${list.message}\n`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
18
30
|
const packet = await d.getFixPacket(interfaceId);
|
|
19
31
|
writeFixRequest(config.projectRoot, interfaceId, packet);
|
|
20
32
|
d.stdout.write(`${packet.message}\n`);
|
package/dist/wire.js
CHANGED
|
@@ -159,6 +159,15 @@ export class Wire {
|
|
|
159
159
|
await this.ensureOk(res, `PUT ${this.repoPath('suite_build')}`);
|
|
160
160
|
return (await res.json());
|
|
161
161
|
}
|
|
162
|
+
// GET /repos/:id/red_lamps — the red list (spec 54-1). No parameters: the
|
|
163
|
+
// server names the current version of each map itself, which is the whole
|
|
164
|
+
// point — a fix no longer guesses a digest.
|
|
165
|
+
async getRedList() {
|
|
166
|
+
const url = this.repoPath('red_lamps');
|
|
167
|
+
const res = await this.send('GET', url);
|
|
168
|
+
await this.ensureOk(res, `GET ${url}`);
|
|
169
|
+
return (await res.json());
|
|
170
|
+
}
|
|
162
171
|
// GET /repos/:id/fix_packet?interface_id= — the per-capability repair packet.
|
|
163
172
|
// Relayed down for the host to fix code or accept the change; 422 (non-failed /
|
|
164
173
|
// stale / no suite) surfaces as a WireError carrying the server's business reason.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unitbob",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.14",
|
|
4
4
|
"description": "Unitbob connector — thin local hands for the Unitbob Rails brain. Owns no domain logic: it runs tools, relays bytes over the wire, and prints what the server returns.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -21,7 +21,7 @@ markers, or paths. Do not edit production code, host-owned shared files, the
|
|
|
21
21
|
connector-owned harness, or another slice.
|
|
22
22
|
|
|
23
23
|
After every owned edit, run
|
|
24
|
-
`npx -y --loglevel=error unitbob@0.7.
|
|
24
|
+
`npx -y --loglevel=error unitbob@0.7.14 run-local <branch>` and inspect the machine
|
|
25
25
|
report. Look only at examples or scenarios matching your owned paths or case
|
|
26
26
|
markers. Do not require a green exit code from the whole branch: foreign failures
|
|
27
27
|
and an already-confirmed product red do not widen your scope. Repeat the bounded
|