Skip to content

Commit 0d5554a

Browse files
makseqclaude
andauthored
The ordered path from a task description to a connected node (#5)
This repository already has everything an agent needs to build somebody's node — the contract, the recipe, a correct reference, a black-box harness and the operational steps — and no ordered path through them. The "Create external node" button in the orchestrator generates a prompt telling the user's own coding agent to clone this repository and finish at an image digest, and an agent arriving that way had to infer the sequence from five documents that each assume you already know why you are reading them. So: one section in CLAUDE.md, which Claude Code reads on its own, with a one-line pointer from README.md. Six steps, each pointing at the document that owns the detail. Nothing is restated — a rule written down twice goes stale in one of the two places, and the stale copy is the one somebody is reading. The step that carries the weight is the third, verification, because after the node has been edited the harness is judging the author's container rather than ours. It states the bar honestly, which means saying three things the section would be easier without: that --red-for-real can only differ from the plain run while some test carries expected_red_until_fixed, and none does; that only the conforms_today group has node.py as its subject, and most of it rests on reference-quality or our-policy bases the contract permits a node to fail; and that several of those tests assert this node COPIES its inputs to its outputs, so a node that transforms them goes red honestly. A red test there is a question, not an instruction. CONFORMANCE-BASELINE.md is named for what it is — a measurement of the reference node, not a prediction about anybody else's. One stale statement is corrected in passing. OPERATIONS.md told the reader that a denied pull of the agent image meant the package had not been made public yet, and to ask an admin to publish it. The package IS public now — an anonymous token against ghcr.io returns the manifest with a 200 — so no docker login is needed and the paragraph said the opposite of the truth. A second stale statement is NOT fixed here, because the token pushing this branch has no workflow scope: the conformance workflow's header still explains why CI is green by saying twenty tests are known to fail, which was true before node.py was repaired and is false now. It needs the same treatment, from a push that is allowed to touch .github/workflows/. Verified: the full harness passes on this tree (128 passed, 1 skipped in 138s — the skip is the verbatim-citation check, which needs a checkout of the orchestrator); collection with --print-labels exits 0, so every test still declares a group and a basis; and every relative link and heading anchor added here resolves. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 5e916fb commit 0d5554a

3 files changed

Lines changed: 93 additions & 4 deletions

File tree

‎CLAUDE.md‎

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,88 @@ below exists to serve both without lying to either.
2121
| `conformance/` | A black-box harness: it builds this image, runs it, judges it from the outside only |
2222
| `tests/` | The tests that harness runs |
2323
| `CONFORMANCE-BASELINE.md` | The measured record of what the harness found |
24+
| `CONTRIBUTING.md` | The two-minute version of making this repository your own node |
25+
26+
## Building your own node from this template
27+
28+
**Background**, about this repository and the order to work in. You have somebody's task
29+
description and a clone of this repository, and you have to finish at a node the
30+
orchestrator can run. Every step below points at the document that owns the detail rather
31+
than repeating it, because a rule written down twice goes stale in one of the two places
32+
and the stale copy is the one somebody is reading.
33+
34+
1. **Read before you write.**
35+
[docs/README.md](docs/README.md#how-to-read-this-three-kinds-of-statement) first — it
36+
says how to read the three labels, and it routes everything else — then
37+
[docs/AUTHORING.md](docs/AUTHORING.md#the-recipe) end to end: the recipe, the
38+
[skeleton](docs/AUTHORING.md#the-skeleton), and the
39+
[checklist](docs/AUTHORING.md#the-checklist) you come back to before you ship. Where the
40+
shorter documents leave you guessing, [docs/PROTOCOL.md](docs/PROTOCOL.md) is the
41+
authority; the [shipped-capability matrix](docs/README.md#shipped-capability-matrix) is
42+
what keeps you from building against something the contract models and the orchestrator
43+
does not send.
44+
45+
2. **Implement the task by editing `node.py`.** Copy and edit it; do not rewrite it from
46+
memory. Every one of the [invariants](#invariants-for-nodepy) below is something a
47+
from-scratch version leaves out and a real run then punishes, and
48+
[docs/AUTHORING.md](docs/AUTHORING.md#nodepy-and-this-skeleton) says which of its
49+
choices are choices rather than rules. Another language is fine — nothing here imports
50+
anything from the orchestrator — but then `node.py` is your behavioural reference rather
51+
than your starting point, and the `Dockerfile`, which copies `node.py` and nothing else,
52+
becomes yours to change too.
53+
54+
3. **Verify with the harness. This is the step that makes the difference**, because after
55+
step 2 it is judging **your** container: it builds the image from this repository's own
56+
`Dockerfile` and never patches it. The commands are in
57+
[Running the harness](#running-the-harness) — run them from the repository root, as
58+
written. The bar, honestly:
59+
60+
* `python -m pytest` must be green. Exactly one skip is expected and is not about your
61+
node: the verbatim-citation check, which needs a checkout of the orchestrator.
62+
* `--red-for-real` differs from the plain run only when some test carries
63+
`expected_red_until_fixed`, and none does today — see
64+
[the expected-red mechanism](#the-expected-red-mechanism). Run both anyway: the day
65+
they disagree, a known defect is being absorbed and you want to know whose.
66+
* **A red test is a question, not an instruction.** Only tests in the `conforms_today`
67+
group have `node.py` as their subject today, so nothing you write moves a
68+
`subject_is_platform` or `harness_self_test` result; and most of that group rests on
69+
`basis_reference_quality` or `basis_our_policy`, which by
70+
[the definitions below](#the-three-labels-and-why-they-are-load-bearing) are things
71+
the contract permits a node to do differently. Several assert that this node
72+
**copies** its inputs to its outputs — a node that transforms them fails those
73+
honestly, as `tests/test_inputs.py` says in its own opening docstring. Get the split
74+
for your run from `--print-labels`, read the check, and change your node only if what
75+
you broke is the contract
76+
([docs/CONFORMANCE.md](docs/CONFORMANCE.md#if-a-conformance-directory-exists-in-this-repository)).
77+
* [CONFORMANCE-BASELINE.md](CONFORMANCE-BASELINE.md) measures the **reference** node,
78+
before and after its repair. It is the most useful thing here to read before writing
79+
your own, and it describes nothing about yours: its counts predict nothing about your
80+
run, and it is not a document to rewrite in your node's image.
81+
82+
4. **Build the image and take its digest.** `docker build` first, then whichever of the two
83+
commands in [docs/OPERATIONS.md](docs/OPERATIONS.md#the-image-reference) matches how the
84+
image will travel — the repo digest of a pushed image, or the bare id of one built
85+
locally, which that section explains only resolves on a machine that already holds it.
86+
Use them as they are written rather than a variant of your own.
87+
88+
5. **Write the README the human gets.** What the node does; the input and output
89+
assumptions you made, port names first, since
90+
[docs/AUTHORING.md](docs/AUTHORING.md#1-decide-what-your-node-consumes-and-produces)
91+
explains what those names decide downstream; the two commands from step 4; and the
92+
connect steps from step 6. [CONTRIBUTING.md](CONTRIBUTING.md) is a fair model for length.
93+
94+
6. **Hand back the digest, and where to paste it.** Point the human at the registration
95+
steps instead of summarising them, and hand over the start line the registration reply
96+
prints instead of one you wrote yourself. **BEHAVIOUR.** A node is registered from
97+
Settings, the **External Nodes** tab, **Connect node**, where that digest is pasted; the
98+
reply creates the pool, the deployment and the revision, and prints the agent's
99+
`docker run` line already filled in with the orchestrator's address, the pool name and —
100+
only when that registration minted one — the pool token
101+
([docs/OPERATIONS.md](docs/OPERATIONS.md#registering-a-node), and
102+
[starting the agent](docs/OPERATIONS.md#starting-the-agent) for the general form). That
103+
line is run on the machine that will run your container. Registering is not running:
104+
nothing executes until a pipeline node points at the deployment
105+
([docs/OPERATIONS.md](docs/OPERATIONS.md#pointing-a-pipeline-node-at-your-deployment)).
24106

25107
## The three labels, and why they are load-bearing
26108

‎README.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ the contract happily permits a real node to skip.
4242

4343
So: **start with [docs/](docs/), then copy `node.py` and edit it.**
4444

45+
If you would rather follow a numbered list — and if you are a coding agent working from
46+
somebody's task description, this is the one to follow — the ordered path from that
47+
description to a node the orchestrator can run is
48+
[Building your own node from this template](CLAUDE.md#building-your-own-node-from-this-template)
49+
in `CLAUDE.md`: read the documents, edit `node.py`, prove it with the harness, take the
50+
digest, hand it over.
51+
4552
## What is here
4653

4754
| Path | What it is |
@@ -53,6 +60,7 @@ So: **start with [docs/](docs/), then copy `node.py` and edit it.**
5360
| `tests/` | The tests that harness runs, and `pytest.ini` names the label on each one |
5461
| `CONFORMANCE-BASELINE.md` | What the harness measured against `node.py`, before and after the repair |
5562
| `CONTRIBUTING.md` | Notes on making this repository your own |
63+
| `CLAUDE.md` | The ordered path from a task description to a connected node, and the invariants `node.py` exists to demonstrate |
5664

5765
## Build and run
5866

‎docs/OPERATIONS.md‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,10 @@ that talks to the orchestrator: it enrols once, polls for work, starts your cont
139139
streams its logs back and reports the result. It listens on no port; every connection is
140140
outbound.
141141

142-
**BEHAVIOUR.** The agent image is published at **`ghcr.io/humansignal/lspo-agent:latest`**.
142+
**BEHAVIOUR.** The agent image is published at **`ghcr.io/humansignal/lspo-agent:latest`**,
143+
and the package is **public**: an anonymous pull works and no `docker login` is needed.
143144
`docker run` pulls it for you; `docker pull ghcr.io/humansignal/lspo-agent:latest` fetches
144-
it on its own if you would rather do that first. **If the pull is denied there is nothing
145-
to retry and nothing wrong with the machine**: the package's visibility has not been made
146-
public yet. Ask the workspace admin to make it public, or to grant that account access.
145+
it on its own if you would rather do that first.
147146

148147
Both the Connect reply and the setup command print the start line already filled in —
149148
prefer either of those, because they carry the real pool name and, when that registration

0 commit comments

Comments
 (0)