@zalom/plastic 2.0.2 → 2.0.3
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/PLASTIC.md +2 -1
- package/README.md +40 -33
- package/agents/plastic-enforcer.md +12 -10
- package/agents/plastic-executor.md +2 -1
- package/agents/plastic-primary-advisor.md +2 -2
- package/agents/plastic-secondary-advisor.md +2 -2
- package/docs/help/agent-architecture.md +9 -8
- package/docs/help/agent-report-contract.md +6 -4
- package/docs/help/completion-and-done.md +10 -5
- package/docs/help/human-report-contract.md +23 -20
- package/docs/help/knowledge-graph.md +2 -2
- package/docs/help/lifecycle-and-savepoints.md +9 -5
- package/docs/help/locks-and-worktrees.md +4 -3
- package/docs/help/maintenance-and-revisions.md +2 -2
- package/docs/help/roadmaps.md +13 -9
- package/docs/help/track-1-guided.md +48 -30
- package/docs/help/track-2-auto.md +35 -10
- package/docs/help/track-3-projects-and-roadmaps.md +10 -7
- package/docs/help/tutorial.md +421 -0
- package/package.json +1 -1
- package/scripts/end-intent +88 -44
- package/scripts/lib/cli/commands/intent_end.rb +1 -1
- package/scripts/lib/revisions_writer.rb +1 -2
- package/skills/_decision-tables.md +3 -3
|
@@ -12,11 +12,15 @@ end to end: a piece of work moved through What, Why, How, and Exec, with a finis
|
|
|
12
12
|
Run `plastic update` first, so the commands below match what is
|
|
13
13
|
actually installed.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
This track walks a graph intent: the plan is a `graph.md` of nodes that the runner dispatches.
|
|
16
|
+
For the simpler checklist path, a small Ruby example taken from a new intent to merged code and
|
|
17
|
+
a delivered close, run `plastic help tutorial` instead.
|
|
18
|
+
|
|
19
|
+
Work in a sandbox. Run `plastic intent new` outside any registered project and the intent lands
|
|
20
|
+
in the global store; run it inside a registered throwaway repository and it lands in that
|
|
21
|
+
project's store, and the close can check the merge. The worked example edits the repository's
|
|
22
|
+
README. With no repository, the deliverable is a short written note saved in the intent's own
|
|
23
|
+
directory (see station 5). Either way, nothing in this track touches a real project.
|
|
20
24
|
|
|
21
25
|
## Stations
|
|
22
26
|
|
|
@@ -33,16 +37,15 @@ Checkpoint: open the new file. It already has a real id and a one-line descripti
|
|
|
33
37
|
was hand-typed into it directly. That is the point: intents are always scaffolded by the
|
|
34
38
|
tool, never written by hand.
|
|
35
39
|
|
|
36
|
-
### 2.
|
|
40
|
+
### 2. Read where it stands
|
|
37
41
|
|
|
38
|
-
Run `plastic
|
|
42
|
+
Run `plastic intent show ID`.
|
|
39
43
|
|
|
40
|
-
Artifact:
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
Artifact: none. The command only reads. It prints the intent's state screen, and its `next:`
|
|
45
|
+
line names the step to run: `plastic intent spec ID` while the intent has no spec or graph.
|
|
46
|
+
`plastic continue` reads the same way for the whole project. Neither takes a lock.
|
|
43
47
|
|
|
44
|
-
Checkpoint:
|
|
45
|
-
sessions from editing the same intent at the same time.
|
|
48
|
+
Checkpoint: name the step the `next:` line points at, and why.
|
|
46
49
|
|
|
47
50
|
### 3. Why, rulings one at a time
|
|
48
51
|
|
|
@@ -50,17 +53,20 @@ Run `plastic intent spec` (say "grill me" for a harder, interview-style pass ove
|
|
|
50
53
|
the same ground). It asks conversational prose questions, one at a
|
|
51
54
|
time, never a multiple-choice menu, and answers them one at a time in return.
|
|
52
55
|
|
|
53
|
-
Artifact:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
Artifact: each ruling lands as its own `## Insights` entry the moment it is made, never batched
|
|
57
|
+
for later, through `plastic intent rule ID "TEXT"`, stamped with the time, the `Why` stage and
|
|
58
|
+
the `human` author. `intent rule` writes nothing else: the agent edits `## Context` and any
|
|
59
|
+
`### Decisions` list by hand. This station's product is the enriched Why; neither command
|
|
60
|
+
writes `spec.md`.
|
|
57
61
|
|
|
58
62
|
Checkpoint: after two or three answers, look at the intent file. Every ruling given out loud
|
|
59
|
-
is already sitting in
|
|
63
|
+
is already sitting in `## Insights`, in writing.
|
|
60
64
|
|
|
61
65
|
### 4. How, write the graph
|
|
62
66
|
|
|
63
|
-
|
|
67
|
+
In the same conversation, the agent turns the rulings into the graph. It writes `graph.md` from
|
|
68
|
+
`templates/graph.md`. No command creates it; once it exists, the runner behind
|
|
69
|
+
`plastic intent step` and `plastic intent answer` updates it.
|
|
64
70
|
|
|
65
71
|
Artifact: `graph.md` (nodes, edges, dispatch policy) and one `nodes/N.md` file per node this
|
|
66
72
|
small delivery needs. A delivery this size is one node; many independent tasks instead get
|
|
@@ -70,35 +76,47 @@ Checkpoint: open `graph.md` and point at the one node this worked example needs.
|
|
|
70
76
|
|
|
71
77
|
### 5. Exec, drive the runner loop
|
|
72
78
|
|
|
73
|
-
Run `plastic intent step`.
|
|
79
|
+
Run `plastic intent step ID`.
|
|
80
|
+
|
|
81
|
+
Graph execution needs the delivery lock. Without it, `intent step` names
|
|
82
|
+
`plastic auto take ID` as the next step. From a conversation session, `auto take` refuses with
|
|
83
|
+
exit 3 unless the owner approves `--allow-inline`; stop and report the refusal.
|
|
74
84
|
|
|
75
|
-
Teach the loop: `
|
|
76
|
-
prints a spawn block to dispatch
|
|
77
|
-
|
|
78
|
-
closes a node that
|
|
79
|
-
|
|
85
|
+
Teach the loop: `plastic intent step ID` runs the internal `runner step`, which computes which
|
|
86
|
+
nodes are ready and prints a spawn block to dispatch. Pass a returned node back with
|
|
87
|
+
`plastic intent step ID --return NODE=PATH`. `plastic intent answer ID --node NODE --decision
|
|
88
|
+
"TEXT"` closes a node that waits on an owner's ruling. The internal
|
|
89
|
+
`ruby ~/.plastic/scripts/runner status <intent_dir>` reads the ledger (running, done, blocked,
|
|
90
|
+
or waiting on a decision); no public command wraps it. Call `step` again after each
|
|
91
|
+
dispatched node returns, until the graph is empty.
|
|
80
92
|
|
|
81
93
|
Artifact: the actual change on disk (the new README Usage section, or, in the global-store
|
|
82
94
|
fallback, a short written note saved as the intent's deliverable) and every node in
|
|
83
95
|
`graph.md` at a terminal status.
|
|
84
96
|
|
|
85
97
|
Checkpoint: run `runner status` and confirm no node is left running or blocked, before
|
|
86
|
-
moving to station 6.
|
|
98
|
+
moving to station 6. When the graph is complete, `intent step` names `plastic intent verify ID`.
|
|
87
99
|
|
|
88
100
|
### 6. End
|
|
89
101
|
|
|
90
|
-
Run `plastic intent end`.
|
|
102
|
+
Run `plastic intent end ID --delivered --summary "TEXT"`. Add `--dry-run` first to see what
|
|
103
|
+
the close would do without writing anything.
|
|
104
|
+
|
|
105
|
+
When the intent has a code branch or worktree, merge the branch yourself first. Plastic does
|
|
106
|
+
not merge, and a delivered close refuses unmerged code with exit 1.
|
|
91
107
|
|
|
92
|
-
Artifact: a real `outcome.md` (Summary, Delivered, Verification, Follow-ups) generated
|
|
93
|
-
`
|
|
94
|
-
to `## Completed` in `INDEX.md`,
|
|
108
|
+
Artifact: a real `outcome.md` (Summary, Delivered, Verification, Follow-ups) generated from
|
|
109
|
+
`graph.md` and the ledger (the same model as the internal `scripts/outcome-report`), the
|
|
110
|
+
intent moved from `## Active` to `## Completed` in `INDEX.md`, the terminal savepoint line,
|
|
111
|
+
and the lock and worktree released.
|
|
95
112
|
|
|
96
113
|
Checkpoint: open `outcome.md` and read its Summary. It should describe, in a sentence or
|
|
97
114
|
two, exactly the README section (or note) just delivered.
|
|
98
115
|
|
|
99
116
|
## Wrap and where to go next
|
|
100
117
|
|
|
101
|
-
That is the full cycle once: create, graph, runner step, end.
|
|
118
|
+
That is the full cycle once: create, graph, runner step, end. Run `plastic help tutorial` for
|
|
119
|
+
the checklist path with a merged code change. Read
|
|
102
120
|
[`your-first-intent-in-10-minutes.md`](https://github.com/zalom/plastic/blob/main/docs/guides/your-first-intent-in-10-minutes.md) for the same path condensed to a single
|
|
103
121
|
read, and [`reading-the-ledgers.md`](https://github.com/zalom/plastic/blob/main/docs/guides/reading-the-ledgers.md) for where each station wrote its
|
|
104
122
|
work down.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Who it is for and what you will have done
|
|
4
4
|
|
|
5
5
|
For someone who has seen the stages once (track 1) and now wants to hand the work to the
|
|
6
|
-
agent, watch it move through the
|
|
6
|
+
agent, watch it move through the stages and reports on its own, and learn how to check in on
|
|
7
7
|
it and step back in later. After this track, one small intent will have been delivered by the
|
|
8
8
|
agent end to end, and pausing and resuming that delivery will feel familiar.
|
|
9
9
|
|
|
@@ -22,12 +22,26 @@ track touches a real project.
|
|
|
22
22
|
Start from an active intent (create one first with `plastic intent new` if none
|
|
23
23
|
exists, the same way as track 1 station 1). Run `plastic auto take ID`.
|
|
24
24
|
|
|
25
|
-
Artifact: the delivery lock arms
|
|
26
|
-
|
|
25
|
+
Artifact: the delivery lock arms (`delivery.lock` in the intent directory) and the code
|
|
26
|
+
worktree is made at `<repo>/.claude/worktrees/ID--slug` on branch `plastic/ID--slug`. The
|
|
27
|
+
command prints both:
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
```text
|
|
30
|
+
intent 2--shout
|
|
31
|
+
lock acquired by auto-9184f6c4fa, auto mode
|
|
32
|
+
worktree /home/you/greeter/.claude/worktrees/2--shout
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Run from inside a conversation session, `plastic auto take` refuses with exit 3: an intent is
|
|
36
|
+
not delivered inline. The owner may approve an inline take with `--allow-inline`. Otherwise
|
|
37
|
+
the harness spawns the team, and the team takes the intent. Exit 3 means stop and report; never
|
|
38
|
+
retry with another flag on your own.
|
|
39
|
+
|
|
40
|
+
`plastic auto brief ID` prints the preamble the spawned lead starts from, and
|
|
41
|
+
`plastic auto lock status ID` shows who holds the lock.
|
|
42
|
+
|
|
43
|
+
Checkpoint: name the one precondition auto needs before it will start: the intent you name
|
|
44
|
+
must already exist in the store the command resolves to.
|
|
31
45
|
|
|
32
46
|
### 2. What auto does, and what stays with the user
|
|
33
47
|
|
|
@@ -39,7 +53,7 @@ working copy with the main line before touching anything, ticks each task the mo
|
|
|
39
53
|
lands rather than batching several into one later edit, and independently verifies its own
|
|
40
54
|
work (running the test suite, or checking the changed file) before presenting anything back
|
|
41
55
|
to you. For a task shaped like an audit or a sweep, checking many files rather than building
|
|
42
|
-
one artifact, it also drops a short methods report into `resources/` before the
|
|
56
|
+
one artifact, it also drops a short methods report into `resources/` before the close, so you
|
|
43
57
|
can review how it checked, not just what it found.
|
|
44
58
|
|
|
45
59
|
The user keeps two things: the rulings made along the way, and the review points, moments
|
|
@@ -76,13 +90,24 @@ line.
|
|
|
76
90
|
|
|
77
91
|
Run `plastic continue`.
|
|
78
92
|
|
|
79
|
-
Artifact: the
|
|
80
|
-
|
|
81
|
-
|
|
93
|
+
Artifact: where the project stands and a `next:` line naming what runs next. `plastic
|
|
94
|
+
continue` only reads: it takes no lock and changes no file. To resume one intent, run
|
|
95
|
+
`plastic intent show ID`; its Next row names the step it resumes at, read from the files on
|
|
96
|
+
disk.
|
|
82
97
|
|
|
83
98
|
Checkpoint: after stepping away and running this command, name the stage the intent resumed
|
|
84
99
|
at and how that matched what was actually on disk.
|
|
85
100
|
|
|
101
|
+
### 6. The close
|
|
102
|
+
|
|
103
|
+
The lead closes the intent with `plastic intent end ID --delivered --summary "TEXT"`. The
|
|
104
|
+
close checks that the code branch is merged and refuses with exit 1 when it is not; Plastic
|
|
105
|
+
does not merge. It also refuses to deliver an untouched scaffold. On success it writes
|
|
106
|
+
`outcome.md` from the record, moves the intent to `## Completed`, and releases the lock and
|
|
107
|
+
the worktree.
|
|
108
|
+
|
|
109
|
+
Checkpoint: open `outcome.md` and read its Summary.
|
|
110
|
+
|
|
86
111
|
## Wrap and where to go next
|
|
87
112
|
|
|
88
113
|
Auto keeps the same stages and the same record as thinking; the only difference is who steers.
|
|
@@ -20,8 +20,8 @@ one this tutorial keeps or ships.
|
|
|
20
20
|
|
|
21
21
|
### 1. Start from a founding implementation intent
|
|
22
22
|
|
|
23
|
-
Create and
|
|
24
|
-
then `plastic
|
|
23
|
+
Create an intent and read where it stands, the same way as track 1, stations 1 and 2:
|
|
24
|
+
`plastic intent new`, then `plastic intent show ID`. Describe something meant to grow into a small real project,
|
|
25
25
|
for example "build a personal todo app."
|
|
26
26
|
|
|
27
27
|
Then type `plastic intent spec` and record a couple of real rulings on this founding
|
|
@@ -66,8 +66,10 @@ and an append-only, dated `## Log`. `INDEX.md` stays the single source of truth
|
|
|
66
66
|
intent's status; the roadmap only mirrors it. List the two or more intents from station 3
|
|
67
67
|
across one or more batches.
|
|
68
68
|
|
|
69
|
-
Run `plastic roadmap check <slug>` to confirm the file parses
|
|
70
|
-
|
|
69
|
+
Run `plastic roadmap check <slug>` to confirm the file parses. A roadmap copied from the
|
|
70
|
+
template may have no `## Graph` section yet; `check` then exits 1 and names
|
|
71
|
+
`plastic roadmap migrate <slug>`, which writes the section from the batches. Then run
|
|
72
|
+
`plastic roadmap show <slug>` to see it rendered as a report.
|
|
71
73
|
|
|
72
74
|
Artifact: a new `roadmaps/<slug>.md` file, sitting next to the project's `INDEX.md`, listing
|
|
73
75
|
the two or more intents from station 3 across one or more batches.
|
|
@@ -101,13 +103,14 @@ sections you turned into the condition above.
|
|
|
101
103
|
No command run here; describe the step instead. Each delivered intent's code merges to main
|
|
102
104
|
as it lands. When the batch (or a meaningful slice of it) is ready to ship, cutting a release
|
|
103
105
|
is a push to `alpha`, `beta`, or `main`: the version files are bumped in that push, and CI
|
|
104
|
-
tags
|
|
106
|
+
tags and publishes. CI never sees your stores, so it closes no intent: each intent is closed
|
|
107
|
+
with `plastic intent end ID --delivered --summary "TEXT"` after its code is merged.
|
|
105
108
|
|
|
106
109
|
Releases and any npm publish step are described here, not run: this walkthrough stays in a
|
|
107
110
|
sandbox and never touches a real package registry.
|
|
108
111
|
|
|
109
|
-
Checkpoint: explain why
|
|
110
|
-
|
|
112
|
+
Checkpoint: explain why an intent closes when its code is merged, rather than waiting on a
|
|
113
|
+
release to exist first.
|
|
111
114
|
|
|
112
115
|
## Wrap and where to go next
|
|
113
116
|
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
# Tutorial: from a new intent to merged, delivered code
|
|
2
|
+
|
|
3
|
+
## What you will do
|
|
4
|
+
|
|
5
|
+
This tutorial takes one small change to a Ruby project from a new intent to a delivered
|
|
6
|
+
close. You create the intent, record a ruling, write the spec, plan, and checklist, make the
|
|
7
|
+
change on a branch with a failing test first, merge the branch, and close the intent as
|
|
8
|
+
delivered. At the end, the intent sits under `## Completed` with the `outcome.md` you wrote and
|
|
9
|
+
a verification that passed.
|
|
10
|
+
|
|
11
|
+
The tutorial uses the checklist path, which needs no hooks, no lock, and no agent team. Every
|
|
12
|
+
command here was run in a disposable `HOME` and `PLASTIC_HOME`. The output blocks come from
|
|
13
|
+
that run, and some are shortened. Paths, times, commit hashes, and lock names differ on your
|
|
14
|
+
machine: `/home/you` stands for your home directory.
|
|
15
|
+
|
|
16
|
+
Plastic records the work. It does not write the spec, the code, or the Git history for you.
|
|
17
|
+
Each step says who does it:
|
|
18
|
+
|
|
19
|
+
- **Plastic**: a `plastic` command.
|
|
20
|
+
- **You or your agent**: writing a file, running tests, or running Git.
|
|
21
|
+
|
|
22
|
+
## Before you start
|
|
23
|
+
|
|
24
|
+
- Plastic is installed. `plastic version` prints a version.
|
|
25
|
+
- Ruby and Git are on your `PATH`.
|
|
26
|
+
- To try the tutorial without touching your real stores, open a new shell, point `HOME` and
|
|
27
|
+
`PLASTIC_HOME` at a scratch directory, and install there first. Type `exit` at the end to
|
|
28
|
+
return to your normal `HOME`:
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
bash
|
|
32
|
+
export HOME=/tmp/plastic-tutorial/home
|
|
33
|
+
export PLASTIC_HOME="$HOME/.plastic"
|
|
34
|
+
export PATH="$PLASTIC_HOME/bin:$PATH"
|
|
35
|
+
mkdir -p "$HOME/.claude"
|
|
36
|
+
npx -y @zalom/plastic install --claude
|
|
37
|
+
hash -r
|
|
38
|
+
command -v plastic
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The installer needs an existing `~/.claude` directory. It stops with `.claude not found`
|
|
42
|
+
otherwise. It places the `plastic` command at `$PLASTIC_HOME/bin/plastic`, and
|
|
43
|
+
`command -v plastic` must print that path. If it prints another path, the commands below
|
|
44
|
+
would run your normal installation.
|
|
45
|
+
- In that shell, check that Ruby can load Minitest: `ruby -e 'require "minitest"'`. Some Ruby
|
|
46
|
+
builds do not include it, and gems installed under your normal `HOME` may not be found from
|
|
47
|
+
the scratch one. Run `gem install minitest` if the check fails.
|
|
48
|
+
|
|
49
|
+
## 1. Create a small Ruby project
|
|
50
|
+
|
|
51
|
+
**You.** Create a Git repository named `greeter` with one method and one test:
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
# lib/greeter.rb
|
|
55
|
+
# frozen_string_literal: true
|
|
56
|
+
|
|
57
|
+
module Greeter
|
|
58
|
+
def self.greet(name)
|
|
59
|
+
"Hello, #{name}!"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```ruby
|
|
65
|
+
# test/greeter_test.rb
|
|
66
|
+
# frozen_string_literal: true
|
|
67
|
+
|
|
68
|
+
require "minitest/autorun"
|
|
69
|
+
require "greeter"
|
|
70
|
+
|
|
71
|
+
class GreeterTest < Minitest::Test
|
|
72
|
+
def test_greets_by_name
|
|
73
|
+
assert_equal "Hello, Ada!", Greeter.greet("Ada")
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Add an `AGENTS.md` file at the repository root. `plastic project new` refuses to register a
|
|
79
|
+
repository without one. A line or two describing the project is enough.
|
|
80
|
+
|
|
81
|
+
Commit everything on `main`. A scratch `HOME` has no Git identity, so set one for this
|
|
82
|
+
repository first, with your own name and email:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
git init -b main
|
|
86
|
+
git config user.name "Your Name"
|
|
87
|
+
git config user.email "you@example.com"
|
|
88
|
+
git add .
|
|
89
|
+
git commit -m "chore: greeter"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 2. Register the project
|
|
93
|
+
|
|
94
|
+
**Plastic.** From inside the repository, run:
|
|
95
|
+
|
|
96
|
+
```sh
|
|
97
|
+
plastic project new greeter --path "$PWD"
|
|
98
|
+
plastic project links
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`project new` creates the project store at `~/.plastic/stores/greeter/` and records the
|
|
102
|
+
repository path in `~/.plastic/projects.yml`. Every later command run inside this repository
|
|
103
|
+
resolves to the `greeter` store. From anywhere else, add `--project greeter`.
|
|
104
|
+
|
|
105
|
+
## 3. Create the intent (What)
|
|
106
|
+
|
|
107
|
+
**Plastic.** Run:
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
plastic intent new "Let Greeter.greet take an optional greeting word" --slug custom-greeting
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The output names the new intent directory and the next step:
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
/home/you/.plastic/stores/greeter/store/1--custom-greeting
|
|
117
|
+
next: plastic intent spec 1 --project greeter
|
|
118
|
+
because: a new intent has no specification yet
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The directory holds the intent file `1--custom-greeting.md`, placeholder files `spec.md`,
|
|
122
|
+
`plan.md`, `checklist.md`, and `outcome.md`, and empty `actions/` and `resources/` folders.
|
|
123
|
+
The intent is listed under `## Active` in `~/.plastic/stores/greeter/INDEX.md`.
|
|
124
|
+
|
|
125
|
+
## 4. Record the rulings (Why)
|
|
126
|
+
|
|
127
|
+
**Plastic.** Run `plastic intent spec 1`. It prints the intent's state screen and the rules the
|
|
128
|
+
speccing conversation follows: one question at a time, two or three approaches with a
|
|
129
|
+
recommendation, and every ruling recorded the moment it lands.
|
|
130
|
+
|
|
131
|
+
**You and your agent** hold that conversation. When a ruling lands, record it:
|
|
132
|
+
|
|
133
|
+
```sh
|
|
134
|
+
plastic intent rule 1 "Keep the default greeting Hello so existing callers are unchanged"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The command prints one `appended:` line. The ruling is appended to the intent file's
|
|
138
|
+
`## Insights` section, stamped with the time, the `Why` stage, and the `human` author, followed
|
|
139
|
+
by the ruling text.
|
|
140
|
+
|
|
141
|
+
`intent rule` writes only to `## Insights`. If you keep a `### Decisions` list in the intent
|
|
142
|
+
file, write it yourself.
|
|
143
|
+
|
|
144
|
+
## 5. Write the spec, the plan, and the checklist (How)
|
|
145
|
+
|
|
146
|
+
**You or your agent** write three files in the intent directory. No command writes them. Each
|
|
147
|
+
file replaces the placeholder that `intent new` created.
|
|
148
|
+
|
|
149
|
+
`spec.md` states the accepted scope:
|
|
150
|
+
|
|
151
|
+
```markdown
|
|
152
|
+
# Spec: Optional greeting word
|
|
153
|
+
|
|
154
|
+
## Problem
|
|
155
|
+
`Greeter.greet` always says "Hello". Callers cannot choose another greeting.
|
|
156
|
+
|
|
157
|
+
## Goals
|
|
158
|
+
- `Greeter.greet("Ada", greeting: "Hi")` returns "Hi, Ada!".
|
|
159
|
+
|
|
160
|
+
## Non-Goals
|
|
161
|
+
- Translation.
|
|
162
|
+
|
|
163
|
+
## Approach
|
|
164
|
+
Add a keyword argument with the default "Hello".
|
|
165
|
+
|
|
166
|
+
## Decisions
|
|
167
|
+
- The default stays "Hello", so existing callers are unchanged.
|
|
168
|
+
|
|
169
|
+
## Acceptance Criteria
|
|
170
|
+
- [ ] The new test passes and the old test still passes.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`plan.md` follows `templates/plan.md`: a `## Goal`, the `## Steps`, and `## Notes`.
|
|
174
|
+
`checklist.md` follows `templates/checklist.md`, with one checkbox for each piece of work:
|
|
175
|
+
|
|
176
|
+
```markdown
|
|
177
|
+
# Checklist: Optional greeting word
|
|
178
|
+
|
|
179
|
+
## In Progress
|
|
180
|
+
- [ ] Add a failing test for the greeting keyword
|
|
181
|
+
- [ ] Add the greeting keyword to Greeter.greet
|
|
182
|
+
|
|
183
|
+
## Completed
|
|
184
|
+
(move items here when done)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Plastic.** `plastic intent show 1` now reads the checklist and points at execution:
|
|
188
|
+
|
|
189
|
+
```text
|
|
190
|
+
| S1 | open | Add a failing test for the greeting keyword |
|
|
191
|
+
| S2 | open | Add the greeting keyword to Greeter.greet |
|
|
192
|
+
next: plastic intent step 1 --project greeter
|
|
193
|
+
because: the checklist has unfinished work
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Until `spec.md` is written, the same screen points back at `plastic intent spec 1`. Until
|
|
197
|
+
`plan.md` and `checklist.md` are written, it says so in the `because:` line.
|
|
198
|
+
|
|
199
|
+
## 6. Do the work (Exec)
|
|
200
|
+
|
|
201
|
+
**Plastic.** `plastic intent step 1` prints the next unchecked item. On a checklist intent, it
|
|
202
|
+
does not run anything:
|
|
203
|
+
|
|
204
|
+
```text
|
|
205
|
+
work Add a failing test for the greeting keyword
|
|
206
|
+
checklist /home/you/.plastic/stores/greeter/store/1--custom-greeting/checklist.md
|
|
207
|
+
|
|
208
|
+
next: none
|
|
209
|
+
because: perform this checklist item, record its verification, then run plastic intent show 1 --project greeter
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**You or your agent** do the item on a branch. The branch name `plastic/1--custom-greeting`
|
|
213
|
+
matches the name `plastic auto take` would provision, so the close can find it:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
git switch -c plastic/1--custom-greeting
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Add the new test to `test/greeter_test.rb`:
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
def test_takes_a_greeting_word
|
|
223
|
+
assert_equal "Hi, Ada!", Greeter.greet("Ada", greeting: "Hi")
|
|
224
|
+
end
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Run the tests and watch the new one fail:
|
|
228
|
+
|
|
229
|
+
```sh
|
|
230
|
+
ruby -Ilib test/greeter_test.rb
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```text
|
|
234
|
+
ArgumentError: wrong number of arguments (given 2, expected 1)
|
|
235
|
+
2 runs, 1 assertions, 0 failures, 1 errors, 0 skips
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Commit the red test. Then tick the item in `checklist.md` in the intent directory: change
|
|
239
|
+
`- [ ]` to `- [x]`.
|
|
240
|
+
|
|
241
|
+
Run `plastic intent step 1` again for the second item. Change `lib/greeter.rb`:
|
|
242
|
+
|
|
243
|
+
```ruby
|
|
244
|
+
module Greeter
|
|
245
|
+
def self.greet(name, greeting: "Hello")
|
|
246
|
+
"#{greeting}, #{name}!"
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Run the tests again. Both pass:
|
|
252
|
+
|
|
253
|
+
```text
|
|
254
|
+
2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Commit, and tick the second item. `plastic intent show 1` now points at
|
|
258
|
+
`plastic intent verify 1`, because every checklist item is complete.
|
|
259
|
+
|
|
260
|
+
To keep the commit on the record, add a note to the savepoint. Replace `<sha>` with the commit
|
|
261
|
+
hash:
|
|
262
|
+
|
|
263
|
+
```sh
|
|
264
|
+
plastic intent note 1 "<sha> greeting keyword, tests green" --kind Commit
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## 7. Write the outcome and verify
|
|
268
|
+
|
|
269
|
+
**You or your agent** replace the `outcome.md` placeholder in the intent directory. The shape
|
|
270
|
+
follows `templates/outcome.md`. The `disposition` must match the close you plan, and each
|
|
271
|
+
`## Delivered` row names one checklist step:
|
|
272
|
+
|
|
273
|
+
```markdown
|
|
274
|
+
---
|
|
275
|
+
disposition: delivered
|
|
276
|
+
---
|
|
277
|
+
# Outcome: Let Greeter.greet take an optional greeting word
|
|
278
|
+
|
|
279
|
+
## Summary
|
|
280
|
+
Greeter.greet takes an optional greeting word; the default stays Hello.
|
|
281
|
+
|
|
282
|
+
## Delivered
|
|
283
|
+
| Row | What |
|
|
284
|
+
| --- | --- |
|
|
285
|
+
| S1 | A test for the greeting keyword |
|
|
286
|
+
| S2 | The greeting keyword on Greeter.greet |
|
|
287
|
+
|
|
288
|
+
## Verification
|
|
289
|
+
- The new test passes and the old test still passes: `ruby -Ilib test/greeter_test.rb` printed 2 runs, 0 failures.
|
|
290
|
+
|
|
291
|
+
## Needs you
|
|
292
|
+
None
|
|
293
|
+
|
|
294
|
+
## Follow-ups
|
|
295
|
+
None
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Plastic.** Record what you verified as a report note:
|
|
299
|
+
|
|
300
|
+
```sh
|
|
301
|
+
plastic intent note 1 "Both greeter tests pass on the branch; outcome.md written" --kind Report
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
`--kind` takes `Review`, `Commit`, or `Report`. Without it, the note is a `Report`.
|
|
305
|
+
|
|
306
|
+
Then run `plastic intent verify 1`. It runs the per-intent doctor check, the em-dash guard,
|
|
307
|
+
and a diffstat of the code branch against `main`. Every check passes, and the command exits 0:
|
|
308
|
+
|
|
309
|
+
```text
|
|
310
|
+
doctor: pass
|
|
311
|
+
em-dash guard: pass (0 violations)
|
|
312
|
+
diffstat against main:
|
|
313
|
+
lib/greeter.rb | 4 ++--
|
|
314
|
+
test/greeter_test.rb | 4 ++++
|
|
315
|
+
2 files changed, 6 insertions(+), 2 deletions(-)
|
|
316
|
+
report lines:
|
|
317
|
+
2026-09-23T11:50:28Z Report Both greeter tests pass on the branch; outcome.md written
|
|
318
|
+
next: plastic intent end 1 --delivered --summary "TEXT" --project greeter
|
|
319
|
+
because: a clean verify is what makes the close trustworthy
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
If a check fails, fix what it names and run `plastic intent verify 1` again. Do not close the
|
|
323
|
+
intent while verify fails.
|
|
324
|
+
|
|
325
|
+
## 8. Merge the code (Git)
|
|
326
|
+
|
|
327
|
+
Plastic does not merge. Its delivered close refuses code that is not merged.
|
|
328
|
+
|
|
329
|
+
**Plastic.** Try the close while the repository is still on the code branch:
|
|
330
|
+
|
|
331
|
+
```sh
|
|
332
|
+
plastic intent end 1 --delivered --summary "Greeter.greet takes an optional greeting word; the default stays Hello."
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
It exits 1 and writes nothing:
|
|
336
|
+
|
|
337
|
+
```text
|
|
338
|
+
end-intent: refusing a delivered close: the repo checkout /home/you/greeter is on the code branch plastic/1--custom-greeting itself, so the code is not merged anywhere. Check out the branch you release from, merge plastic/1--custom-greeting into it, then run the close again
|
|
339
|
+
end-intent: nothing was merged, written, or released
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**You.** Merge the branch and run the tests on `main`:
|
|
343
|
+
|
|
344
|
+
```sh
|
|
345
|
+
git switch main
|
|
346
|
+
git merge --no-ff plastic/1--custom-greeting
|
|
347
|
+
ruby -Ilib test/greeter_test.rb
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## 9. Close the intent as delivered
|
|
351
|
+
|
|
352
|
+
**Plastic.** Preview the close first:
|
|
353
|
+
|
|
354
|
+
```sh
|
|
355
|
+
plastic intent end 1 --delivered --summary "Greeter.greet takes an optional greeting word; the default stays Hello." --dry-run
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The dry run lists what the close would do: move the `INDEX.md` entry to `## Completed`, append
|
|
359
|
+
the terminal savepoint line, commit the store repository, and release the lock and the code
|
|
360
|
+
worktree. It ends with:
|
|
361
|
+
|
|
362
|
+
```text
|
|
363
|
+
next: none
|
|
364
|
+
because: the dry run wrote nothing and found nothing that would refuse the close
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Run the same command without `--dry-run`. The close fills the records that are still
|
|
368
|
+
placeholders from the record itself. Here that is the action file:
|
|
369
|
+
|
|
370
|
+
```text
|
|
371
|
+
end-intent: backfilled actions/ACTION_1.md from the record
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
`plastic intent show 1` now shows both steps done:
|
|
375
|
+
|
|
376
|
+
```text
|
|
377
|
+
next: none
|
|
378
|
+
because: the intent is completed
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
`outcome.md` keeps what you wrote. The close writes the `--summary` text into the intent file's
|
|
382
|
+
`## Outcome` section.
|
|
383
|
+
|
|
384
|
+
## The same change in auto mode
|
|
385
|
+
|
|
386
|
+
In auto mode, an agent team does steps 4 to 9. The commands below set up and inspect that
|
|
387
|
+
run. They do not run the team; your harness does that.
|
|
388
|
+
|
|
389
|
+
1. `plastic auto take ID` takes the delivery lock and provisions the code worktree at
|
|
390
|
+
`<repo>/.claude/worktrees/ID--slug` on branch `plastic/ID--slug`.
|
|
391
|
+
|
|
392
|
+
```text
|
|
393
|
+
intent 2--shout
|
|
394
|
+
lock acquired by auto-9184f6c4fa, auto mode
|
|
395
|
+
worktree /home/you/greeter/.claude/worktrees/2--shout
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Run from inside a conversation session, `auto take` refuses with exit 3 unless you pass
|
|
399
|
+
`--allow-inline`. Exit 3 means the step belongs to the owner: stop and report it.
|
|
400
|
+
|
|
401
|
+
2. `plastic auto brief ID` prints the preamble the dispatched agent reads first.
|
|
402
|
+
3. `plastic auto lock status ID` shows who holds the lock and where the worktree is.
|
|
403
|
+
4. `plastic auto report ID` prints the report contract and the review rules the lead follows.
|
|
404
|
+
5. The close is the same `plastic intent end` as in step 9, with the same merge check.
|
|
405
|
+
|
|
406
|
+
`plastic intent end ID --delivered` refuses an intent that nobody worked on. The spec, plan,
|
|
407
|
+
checklist, and outcome are still placeholders, and the worktree has no changes. Close it with
|
|
408
|
+
`--abandoned` instead:
|
|
409
|
+
|
|
410
|
+
```sh
|
|
411
|
+
plastic intent end 2 --abandoned --summary "Probe of the auto contract only."
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
The abandoned close also removes the code worktree.
|
|
415
|
+
|
|
416
|
+
## Where to go next
|
|
417
|
+
|
|
418
|
+
- `plastic help track-1-guided`: the same cycle for a graph intent, driven one node at a time.
|
|
419
|
+
- `plastic help track-2-auto`: how the auto team walks the record.
|
|
420
|
+
- `plastic help completion-and-done`: what the close checks and writes.
|
|
421
|
+
- `plastic help locks-and-worktrees`: the delivery lock and the code worktree.
|