sako 0.5.0__py3-none-any.whl
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.
- sako/SAKO.md +319 -0
- sako/__init__.py +1799 -0
- sako/skills/sako/SKILL.md +20 -0
- sako/templates/TASKS.md +10 -0
- sako-0.5.0.dist-info/METADATA +200 -0
- sako-0.5.0.dist-info/RECORD +9 -0
- sako-0.5.0.dist-info/WHEEL +4 -0
- sako-0.5.0.dist-info/entry_points.txt +2 -0
- sako-0.5.0.dist-info/licenses/LICENSE +21 -0
sako/SAKO.md
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# Working with SAKO
|
|
2
|
+
|
|
3
|
+
The SAKO method, a task ledger and finish gate for coding agents, installed in this
|
|
4
|
+
project. Project instructions and the owner's choices come first; they also name
|
|
5
|
+
the planner or source of work. This file holds no project state.
|
|
6
|
+
|
|
7
|
+
Use SAKO for project tasks here, code and documentation changes and bounded
|
|
8
|
+
investigations alike, without being asked each time. Questions and discussion need
|
|
9
|
+
no task record. Run `python3 .sako/sako.py <command>` (`python` on Windows) from
|
|
10
|
+
anywhere in the repository; from a linked worktree, use the command line the start
|
|
11
|
+
context prints.
|
|
12
|
+
|
|
13
|
+
## Daily loop
|
|
14
|
+
|
|
15
|
+
1. **Start.** The session-start hook prints the context and your session ID.
|
|
16
|
+
Without it, run `start --session <id>` with an ID unique to this conversation.
|
|
17
|
+
Pass the same ID to every command; in Claude Code and Codex, a command
|
|
18
|
+
without `--session` uses the client's session ID, the one the hook used.
|
|
19
|
+
2. **Choose and claim.** Follow the owner's priority. `next` names the task to
|
|
20
|
+
start and why, what else is ready, and what waits. For new work, run
|
|
21
|
+
`add "task" --done-when "observable result" --scope src/`, then
|
|
22
|
+
`claim T-1 --session <id>` with the returned ID. Keep scopes narrow and widen
|
|
23
|
+
them in the ledger before the work grows. If nothing fits, return to the
|
|
24
|
+
selected planner; the table under **Read when needed** covers the rest.
|
|
25
|
+
3. **Work and check.** Use the project's own tools and checks. Run `verify` when a
|
|
26
|
+
check is configured; it records a fingerprint of the checked content. For
|
|
27
|
+
discovery or a manual check, keep the actual findings or procedure and result.
|
|
28
|
+
A passing suite alone is not acceptance: inspect the requested behavior.
|
|
29
|
+
4. **Close and commit.** `close T-1 --session <id> --evidence "result and proof"`
|
|
30
|
+
moves the row to the done record with a receipt: your evidence, then the
|
|
31
|
+
closing marker, the date, and what the check said. State the outcome and its
|
|
32
|
+
limits, not just "done". Commit the task's work within the owner's
|
|
33
|
+
authorization, staging explicit paths. SAKO never commits, pushes or deploys.
|
|
34
|
+
5. **Finish.** Run `check --gate --session <id>` (the Stop hook runs it too) and
|
|
35
|
+
fix what it names, or report what remains. If you ran `start` yourself, run
|
|
36
|
+
`end --session <id>` last. With hooks, the client ends the session; do not run
|
|
37
|
+
`end`, since the Stop gate needs your start record. Report the result, the
|
|
38
|
+
evidence and the next decision.
|
|
39
|
+
|
|
40
|
+
You can stop incomplete: keep the claim and write its handoff. If commits are not
|
|
41
|
+
authorized, report the reviewed work as uncommitted. A satisfied goal needs no
|
|
42
|
+
new task.
|
|
43
|
+
|
|
44
|
+
## Done means
|
|
45
|
+
|
|
46
|
+
The gate checks this session against three rules. Each finding names its rule and
|
|
47
|
+
ends with the command or edit that fixes it.
|
|
48
|
+
|
|
49
|
+
- **Recorded:** every file the session changed belongs to a task it claimed or closed.
|
|
50
|
+
- **Proven:** a task closed after checked content changed has a passing check.
|
|
51
|
+
- **Committed:** closed work is committed; in the repo and shared footprints, its records too.
|
|
52
|
+
|
|
53
|
+
Pausing is free: claimed, unfinished work passes. Two advisories never block: a
|
|
54
|
+
claimed, unfinished task without a `handoff.md`, and a closed task whose handoff
|
|
55
|
+
folder remains. A clear gate means these rules passed, not that the owner accepts
|
|
56
|
+
the result. A null `verify_command` means no automated evidence: close with the
|
|
57
|
+
manual check's procedure and result, and the receipt says "no automated check". It
|
|
58
|
+
never becomes a pass; do not call that work verified.
|
|
59
|
+
|
|
60
|
+
## Records
|
|
61
|
+
|
|
62
|
+
| Information | Home |
|
|
63
|
+
|---|---|
|
|
64
|
+
| Direction, purpose, acceptance | The project's instructions, brief or README; a task's Source points to its planner item |
|
|
65
|
+
| Active work and ownership | `.sako/work/TASKS.md` |
|
|
66
|
+
| Completed work with receipts | `.sako/work/DONE.md`, created on first close |
|
|
67
|
+
| A paused task's handoff and notes | `.sako/work/T-<n>-<slug>/`, printed by `claim`; you delete it at close |
|
|
68
|
+
| Unresolved decisions | The affected task or the project's context: the question, any assumption, who decides |
|
|
69
|
+
| The owner holds agreed work ("wait until I try it") | That work's row, `parked` with the reason, so a fresh session waits too |
|
|
70
|
+
|
|
71
|
+
```markdown
|
|
72
|
+
| ID | Pri | Task | Done when | Status | Scope | After | Source |
|
|
73
|
+
|---|---|---|---|---|---|---|---|
|
|
74
|
+
| T-1 | P1 | A named visitor receives a greeting | The sample prints Hello, Ada | open | `src/`, `tests/` | - | PLAN.md#N1 |
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
This row is an example, not live work. `Pri` is P1, P2 (empty reads P2) or P3.
|
|
78
|
+
Status's first word is `open` (empty reads open), `parked` with its reason, or the
|
|
79
|
+
claiming session's marker. `After` lists prerequisite IDs. Scopes are
|
|
80
|
+
repository-relative path prefixes; `.` covers everything. The done record keeps
|
|
81
|
+
`ID | Task | Done when | Receipt | Scope | Source`. IDs are never reused. Columns are
|
|
82
|
+
read by name, in any order, and columns you add are kept. Keep a cell on one line,
|
|
83
|
+
without literal pipes. Commands change only their own rows; hand edits are fine but
|
|
84
|
+
not locked, so coordinate them with other sessions.
|
|
85
|
+
|
|
86
|
+
The records live where `status` says: local (`.sako/` is listed in
|
|
87
|
+
`.git/info/exclude`, so they are not in Git, and `git clean -x` deletes them), in
|
|
88
|
+
their own repository inside `.sako/` (repo), or committed with the code (shared,
|
|
89
|
+
one copy per branch).
|
|
90
|
+
|
|
91
|
+
Put each discovery where the next reader needs it: an invariant in the code or test
|
|
92
|
+
that enforces it, a product choice in the project's context, progress and traps in
|
|
93
|
+
the task's handoff. Reference that home from the receipt rather than copying it.
|
|
94
|
+
|
|
95
|
+
## Read when needed
|
|
96
|
+
|
|
97
|
+
The following sections apply only in their situation:
|
|
98
|
+
|
|
99
|
+
| Situation | Section |
|
|
100
|
+
|---|---|
|
|
101
|
+
| Work comes from a plan, checklist, issue or planning skill | Task intake |
|
|
102
|
+
| No planner is selected, direction is unclear, or nothing is ready | No planner? Start here |
|
|
103
|
+
| Pausing, resuming, or a stale claim | Pause, handoff and takeover |
|
|
104
|
+
| Another session works in this repository | Working beside other sessions |
|
|
105
|
+
| A gate finding or check result needs explaining | The gate and checks in detail |
|
|
106
|
+
| Installing, updating, removing, or wiring a worktree | Install, update and remove |
|
|
107
|
+
|
|
108
|
+
## Task intake
|
|
109
|
+
|
|
110
|
+
Read this when work comes from the project's plan, checklist, issue or planning
|
|
111
|
+
skill. Translate the selected work into local rows without replacing its planner or
|
|
112
|
+
copying its backlog. Keep a concrete outcome, a completion condition, a bounded
|
|
113
|
+
scope and known prerequisites; add only details that change execution.
|
|
114
|
+
|
|
115
|
+
1. **Name the source.** Keep the item's authoritative location and a stable
|
|
116
|
+
reference such as `PLAN.md#N1` for `--source`. Give each local action from one
|
|
117
|
+
upstream item its own reference, and reuse it exactly on later intake.
|
|
118
|
+
2. **Record or reuse it.** Put the outcome in the task text and the completion
|
|
119
|
+
condition in `--done-when`. Declare the files with `--scope`, including a source
|
|
120
|
+
document the task will update. Pass the planner's priority with `--pri` and
|
|
121
|
+
prerequisites with `--after`:
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
python3 .sako/sako.py add "Discover note names" --done-when "Filtering and unchanged inputs are checked" --source PLAN.md#N1 --pri P1 --scope src/ --scope tests/
|
|
125
|
+
python3 .sako/sako.py add "Print sorted names" --done-when "The agreed sample matches" --source PLAN.md#N2 --after T-1 --scope preview.py
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Use the IDs the command returns. Prerequisites release when all are done;
|
|
129
|
+
`next` ranks what is ready by priority, then row order.
|
|
130
|
+
3. **Handle repeat or changed input.** The same source, task, completion
|
|
131
|
+
condition, scope and prerequisites reuse the existing ID, completed work
|
|
132
|
+
included. A new `--pri` updates an unfinished task's priority and says so.
|
|
133
|
+
Any other difference refuses instead of replacing work: inspect the source and
|
|
134
|
+
the row, then reconcile deliberately. When an item changed after its task was
|
|
135
|
+
done, record the new work as a new task with its own source, such as
|
|
136
|
+
`PLAN.md#N1-v2`; the done row stays as history. Without `--source`, every `add`
|
|
137
|
+
is a new task.
|
|
138
|
+
4. **Return the result.** Before starting, check that the source item still
|
|
139
|
+
applies. When returning the result edits a file the check covers, such as
|
|
140
|
+
ticking the item's box, make that edit before `verify` and `close`: an edit after
|
|
141
|
+
close needs a fresh check. After close, compare the result with the upstream
|
|
142
|
+
acceptance and return the evidence through the project's authorized procedure,
|
|
143
|
+
or report that update as pending. Local completion does not complete a larger
|
|
144
|
+
upstream item.
|
|
145
|
+
|
|
146
|
+
Source references are exact identifiers; the runtime does not fetch, interpret,
|
|
147
|
+
watch or synchronize them. When a source changes, you judge what it means.
|
|
148
|
+
|
|
149
|
+
## No planner? Start here
|
|
150
|
+
|
|
151
|
+
Read this when no planner or work source is selected and the direction is unclear,
|
|
152
|
+
or nothing is ready. Begin with the owner's request and only as much evidence as
|
|
153
|
+
the next useful action needs: instructions, local changes, entry points, notes and
|
|
154
|
+
checks. Code shows what exists; it does not decide what the owner wants. An old
|
|
155
|
+
checklist is evidence, not an order.
|
|
156
|
+
|
|
157
|
+
| Starting point | Establish first | Preserve |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| An idea, little or no code | Who it helps, the first useful outcome, a constraint that changes the approach | The owner's uncertainty; direction can be provisional |
|
|
160
|
+
| Code with notes, TODOs or a backlog | Which source governs current intent; whether the work is still needed | Existing authority, IDs, conventions, unrelated changes |
|
|
161
|
+
| Code with little explanation | How the relevant behavior works today, what is unknown, what the owner wants next | Working behavior until a change is intended |
|
|
162
|
+
|
|
163
|
+
Ask a small, concrete question only when the answer changes the outcome, scope or
|
|
164
|
+
acceptance; find file locations and commands yourself. Record consequential
|
|
165
|
+
answers and label assumptions. Put just enough in an existing README or brief to
|
|
166
|
+
answer: the **direction** (who it serves, the current outcome), the **starting
|
|
167
|
+
point** (what works, what is unknown), the **boundaries**, the **next action**, and
|
|
168
|
+
what counts as **success**. A short paragraph and one task are often enough; a PRD,
|
|
169
|
+
phases or a full backlog are optional.
|
|
170
|
+
|
|
171
|
+
If intent or feasibility is too uncertain to build, add a bounded investigation:
|
|
172
|
+
the question, the evidence to collect, and when to stop. "Run the import with a
|
|
173
|
+
synthetic sample and record the accepted columns, the failure and the next
|
|
174
|
+
decision" is actionable; "try things until clear" is not. With no automated check,
|
|
175
|
+
leave `verify_command` null and say how the result will be judged; never add an
|
|
176
|
+
always-passing command.
|
|
177
|
+
|
|
178
|
+
When nothing is ready or evidence changes the plan:
|
|
179
|
+
|
|
180
|
+
| The evidence says | Next move |
|
|
181
|
+
|---|---|
|
|
182
|
+
| The outcome is unfinished and nothing is ready | Prepare the smallest justified action |
|
|
183
|
+
| Work is held by a session or a prerequisite | Inspect the owner or blocker; continue your own claim or leave a precise handoff |
|
|
184
|
+
| A decision is missing | Record the question and ask the owner instead of inventing direction |
|
|
185
|
+
| Feedback invalidates planned work | Revise the task or park it with a reason, keeping IDs and references |
|
|
186
|
+
| The outcome is satisfied | Report completion; an empty queue is a valid finish |
|
|
187
|
+
|
|
188
|
+
Do not create tasks to keep agents busy. Bring anything that would widen the agreed
|
|
189
|
+
outcome to the owner first.
|
|
190
|
+
|
|
191
|
+
## Pause, handoff and takeover
|
|
192
|
+
|
|
193
|
+
Read this when you pause unfinished work, resume, or meet a stale claim. Before
|
|
194
|
+
pausing a claimed task, write `handoff.md` in the folder `claim` printed,
|
|
195
|
+
`.sako/work/T-<n>-<slug>/`: where the task stands, what landed, what is left, the
|
|
196
|
+
next step, and traps. Other working notes can sit beside it; plans stay in their
|
|
197
|
+
own home, linked. The folder is found by task ID and is never checked content or an
|
|
198
|
+
unrecorded change. On close, move its lasting facts to their real home and delete
|
|
199
|
+
it. `start` and `status` list open tasks' folders.
|
|
200
|
+
|
|
201
|
+
A new session reads the records, the handoff and the relevant Git diff before it
|
|
202
|
+
continues; `status --session <id>` shows the changes, ownership, evidence and
|
|
203
|
+
commits since that session began. A live owner cannot be replaced. For a stale
|
|
204
|
+
claim, inspect its work, then run `claim T-1 --session <new-id> --takeover "reason"`.
|
|
205
|
+
|
|
206
|
+
Each conversation needs its own session ID, even when several share one host
|
|
207
|
+
process; a resumed conversation reuses its ID. A subagent's shell carries its own
|
|
208
|
+
Claude Code session ID, so it passes the parent's `--session` explicitly.
|
|
209
|
+
|
|
210
|
+
Presence judges liveness by the host process where that process is visible. A
|
|
211
|
+
client's sandbox (Codex runs agent commands in one) hides the host's processes, so
|
|
212
|
+
there, and for a session started inside one, presence counts as live for 24 hours
|
|
213
|
+
after its last `start`, marked unverified. A claim held by an unverified session
|
|
214
|
+
can be taken over with a reason once you have checked that it stopped; the claim
|
|
215
|
+
says its holder was unverified. A session that ran `start` itself runs `end
|
|
216
|
+
--session <id>` when it finishes; otherwise its presence stays until its host
|
|
217
|
+
process exits or its 24 hours pass. Do not end a peer's presence without
|
|
218
|
+
confirming it stopped. `SAKO_AGENT_PID` can name a long-lived host process, never a
|
|
219
|
+
temporary shell.
|
|
220
|
+
|
|
221
|
+
An interrupted close can leave the same row in both records: repeat the exact
|
|
222
|
+
close command with the same evidence and session. Conflicting closed content is
|
|
223
|
+
refused; never delete completed evidence blindly.
|
|
224
|
+
|
|
225
|
+
## Working beside other sessions
|
|
226
|
+
|
|
227
|
+
Read this when another session works in this repository. Every worktree uses the
|
|
228
|
+
main checkout's `.sako/`, so sessions share one ledger, one numbering and one lock.
|
|
229
|
+
A claim refuses a live owner and a scope that overlaps another session's claim.
|
|
230
|
+
The lock serializes `add`, `claim` and `close` only: not application edits, hand
|
|
231
|
+
edits of the records, Git's index or other clones. A push is a record, not a lock.
|
|
232
|
+
Keep scopes disjoint, coordinate direct record edits, and stage explicit paths.
|
|
233
|
+
SAKO does not schedule agents or merge their edits.
|
|
234
|
+
|
|
235
|
+
## The gate and checks in detail
|
|
236
|
+
|
|
237
|
+
Read this when a gate finding or a check result needs explaining. `verify` runs the
|
|
238
|
+
configured argument array at the top of the checkout; use `["bash",
|
|
239
|
+
"scripts/check.sh"]` for shell features. It stamps a pass only when the checked
|
|
240
|
+
content and the command stay unchanged during the run; a failure deletes old
|
|
241
|
+
evidence. The stamp covers the content, paths, symlink text and executable bits of
|
|
242
|
+
unignored files under `verify_paths`; an empty list covers everything outside
|
|
243
|
+
`.sako/`, documentation included. Name product subtrees if documentation-only work
|
|
244
|
+
should not invalidate the check. Dependencies and services need another check by
|
|
245
|
+
judgment. Stamps are local, one per worktree: rerun `verify` after a fresh clone.
|
|
246
|
+
|
|
247
|
+
**Recorded** counts files edited since the session started or committed since then,
|
|
248
|
+
deletions and both sides of a rename; a file already dirty at start counts only when
|
|
249
|
+
it changes again. A live peer's claimed scope in the same checkout is not counted,
|
|
250
|
+
with a note. A linked worktree nested in the checkout, such as one a harness makes
|
|
251
|
+
for a subagent, is another checkout: its work counts once merged. Without a start
|
|
252
|
+
record, every uncommitted change counts and commits go unchecked; the gate says so.
|
|
253
|
+
**Proven:** while a claim you still hold covers changed checked files, a stale check
|
|
254
|
+
is that claim's work in progress, and a close whose receipt shows a pass stays
|
|
255
|
+
proven. **Committed** skips files inside a claim you still hold; its fix applies
|
|
256
|
+
only when the owner allows commits, otherwise say the work awaits approval.
|
|
257
|
+
|
|
258
|
+
`check --gate` prints advisories under a clear result, and a blocked stop lists
|
|
259
|
+
them after its problems; a clear stop stays silent. Hooks fail open on their own
|
|
260
|
+
errors and on a repeated stop, so the gate never traps a session. Exit codes: 0
|
|
261
|
+
success, 1 findings or a failed check, 2 a gate needing attention, 3 an actionable
|
|
262
|
+
refusal, 4 a bug.
|
|
263
|
+
|
|
264
|
+
## Install, update and remove
|
|
265
|
+
|
|
266
|
+
Read this when installing, updating or removing the kit, or wiring a worktree. Run
|
|
267
|
+
`uvx sako init`, or `python3 <checkout>/sako.py init` from a reviewed checkout,
|
|
268
|
+
anywhere in the project's Git repository. It needs no flags. The runtime, this
|
|
269
|
+
method, `install.json`, `config.json` and an empty `work/TASKS.md` land in the main
|
|
270
|
+
checkout's `.sako/`, which is listed in `.git/info/exclude` with the client files
|
|
271
|
+
`init` writes, so nothing tracked changes. The project's instructions stay
|
|
272
|
+
untouched: the start context names the method, the records and the command line.
|
|
273
|
+
|
|
274
|
+
`init` wires SessionStart, Stop and SessionEnd hooks for each client it finds a
|
|
275
|
+
sign of: the Claude Code or Codex session running it, `.claude/` or `CLAUDE.md`
|
|
276
|
+
for Claude Code, `.codex/` for Codex, and `AGENTS.md` for both. It prints the choice and why
|
|
277
|
+
and records it; later runs and `--update` keep it. `--client claude`, `--client
|
|
278
|
+
codex` (repeat for both) or `--client none` replaces it; none means explicit
|
|
279
|
+
`start`, `check --gate` and `end`, also the route for clients without an adapter.
|
|
280
|
+
With no sign of a client, a later `init` detects one that appears, including a
|
|
281
|
+
Claude Code or Codex session running it.
|
|
282
|
+
The shared skill always installs in `.agents/skills/sako/`, and Claude Code gets a
|
|
283
|
+
copy in `.claude/skills/sako/`. Codex runs project hooks only after you trust them;
|
|
284
|
+
`status` says when each client's hook last ran. A tracked settings file is never
|
|
285
|
+
changed; `init` says what to add by hand. A client file whose folder leads
|
|
286
|
+
outside the repository is skipped with a note. A client that reads neither hooks
|
|
287
|
+
nor skills can be pointed to `.sako/SAKO.md` in its instructions.
|
|
288
|
+
|
|
289
|
+
Configure the check in `.sako/config.json`: `verify_command` as an argument array,
|
|
290
|
+
such as `["python3", "-B", "-m", "unittest"]`, and `verify_paths`. In a new linked
|
|
291
|
+
worktree, run `init` there: it wires that worktree for the clients the main
|
|
292
|
+
checkout chose and, for Codex, a writable root for the main `.sako/`, which Codex
|
|
293
|
+
reads once it trusts the project. The records stay in the main checkout.
|
|
294
|
+
|
|
295
|
+
Two footprints put the records in Git. `init --repo [url]` gives them their own
|
|
296
|
+
repository inside `.sako/`, still out of the code's: its `.gitignore` leaves out the
|
|
297
|
+
kit files and `state/`, so it tracks `config.json` and `work/`. With a URL, a
|
|
298
|
+
checkout without records clones them, and existing records get it as `origin`;
|
|
299
|
+
records on both sides refuse. `init --shared` commits the records with the code: it
|
|
300
|
+
takes `.sako/` out of `.git/info/exclude`, prints the commit command, and prints a
|
|
301
|
+
line to add to your instructions so an agent on a fresh clone finds SAKO. Each
|
|
302
|
+
branch then keeps its own copy, so a linked worktree uses its own `.sako/`, and one
|
|
303
|
+
on a branch without a copy refuses. It refuses while `.sako/.git` exists and names
|
|
304
|
+
the move. SAKO commits nothing; the gate's Committed rule asks for the records'
|
|
305
|
+
commit with its exact command. `install.json` records the footprint, and a
|
|
306
|
+
disagreement with Git is a finding. To go back to local, run `remove`, then `init`,
|
|
307
|
+
which names any Git command to run first; the records stay byte for byte. In the
|
|
308
|
+
repo footprint `remove` keeps `.sako/.git` and warns about commits that exist only
|
|
309
|
+
there; the command `init` then names moves that history out of `.sako/`, beside the
|
|
310
|
+
project, where it stays until you delete it.
|
|
311
|
+
|
|
312
|
+
To update, review the new release and run its `init --update` with no active work,
|
|
313
|
+
such as `uvx sako@latest init --update` (plain `uvx sako` can reuse a cached copy).
|
|
314
|
+
Modified kit files refuse; an unmodified one the new choice or release no longer
|
|
315
|
+
needs is deleted. `python3 .sako/sako.py remove` in the main checkout
|
|
316
|
+
removes unmodified kit files, SAKO's hook entries in every worktree and the
|
|
317
|
+
disposable state; `config.json` and `work/` stay, and deleting `.sako/` leaves no
|
|
318
|
+
trace. The client choice goes with `install.json`, so a later `init` detects the
|
|
319
|
+
clients again. The copy in a project cannot seed another project.
|