nawabari 0.1.0 → 0.2.0

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 CHANGED
@@ -24,6 +24,56 @@ git nawabari --help
24
24
  nawabari --version
25
25
  ```
26
26
 
27
+ ## Standalone machine contract
28
+
29
+ The installed CLI/JSON surface is the integration boundary. An orchestrator
30
+ must discover the contract before using the lifecycle:
31
+
32
+ ```bash
33
+ nawabari capabilities --json
34
+ nawabari --version --json
35
+ ```
36
+
37
+ Both discovery commands work without a Git repository. A compatible
38
+ installation reports `contract_id: "nawabari.standalone-execution.v1"` and
39
+ `schema_version: 1`. The capability response lists the exact commands,
40
+ result-schema versions, identity fields, and stable `failure_codes`. The
41
+ package version is release metadata; it is not a substitute for the
42
+ machine-contract identifier.
43
+
44
+ The supported standalone sequence is:
45
+
46
+ ```text
47
+ session create -> session claim(s) -> authorize/checkpoint
48
+ -> commit/push -> doctor (reconciliation) -> session close/gc
49
+ ```
50
+
51
+ The JSON envelope is one document on stdout. Success has `ok: true`, a
52
+ `command`, and the command's versioned result fields. Failure has `ok: false`,
53
+ the `command`, a stable `code`, a bounded human-readable `message`, and
54
+ optional structured `details`; JSON mode writes no decorative stderr. Exit
55
+ codes are `0` success, `2` usage, `3` rejected/unsafe operation, `4`
56
+ unavailable capability, `5` failed doctor checks, and `70` unexpected internal
57
+ failure. Consumers must use these fields and codes, never human presentation.
58
+
59
+ The result schemas expose the following identities:
60
+
61
+ | Surface | Versioned identities |
62
+ | ---------------------- | -------------------------------------------------------------------------------- |
63
+ | session lifecycle | `session_id`, `repository`, `worktree`, `branch`, `state` |
64
+ | claims | `claim_id`, `session_id`, `resource`, `mode` |
65
+ | authorization | `operation`, `allowed`, `code`, `claim_ids` |
66
+ | checkpoint evidence | `head`, `changed`, `staged`, `unstaged`, `untracked`, `in_claim`, `out_of_claim` |
67
+ | commit/push | `commit_sha`, `remote`, `branch`, `target`, `relation` |
68
+ | reconciliation/cleanup | `clean`, `issues`, `candidates`, `cleaned`, `blocked`, `recovery_hints` |
69
+
70
+ Git subprocesses are bounded at 10 seconds and 64 KiB of output; checkpoint
71
+ evidence is bounded to 4,096 paths. `GIT_SPAWN_FAILED`, `GIT_TIMEOUT`,
72
+ `GIT_OUTPUT_LIMIT`, and `GIT_COMMAND_FAILED` remain distinct failure codes.
73
+ The local lifecycle requires Git and the repository-local registry/lock only;
74
+ it does not require Mottainai, GitHub, `gh`, network access, an LLM, or a
75
+ coding-agent runtime.
76
+
27
77
  ## Session lifecycle
28
78
 
29
79
  Session IDs are generated automatically as UUIDv7 values. They are immutable
@@ -52,7 +102,52 @@ state, and commits not proven reachable from the integration branch block
52
102
  destructive cleanup. A clean close releases only the owned worktree and
53
103
  branch, and repeating close is idempotent. `gc` detects stale or interrupted
54
104
  sessions; `--apply` uses the same close safety checks and reports blocked
55
- sessions instead of guessing.
105
+ sessions instead of guessing. `gc --dry-run` performs the same non-mutating
106
+ cleanup preflight and includes stable blocker codes and `recovery_hints` for
107
+ every candidate that is not safe. Cleanup revalidates the physical worktree,
108
+ branch, and `HEAD` observations immediately before each destructive Git
109
+ operation.
110
+
111
+ `doctor` includes a non-destructive `reconciliation` check. It reports
112
+ registry/Git ownership drift, including missing or prunable worktrees and
113
+ unregistered physical worktrees, without repairing or deleting anything.
114
+
115
+ ## Session resource claims
116
+
117
+ Resource claims are versioned, session-scoped ownership records stored in the
118
+ same repository registry and protected by the same mutation lock. They are
119
+ caller declarations; Nawabari does not infer them from task text or source
120
+ code. Claim JSON exposes `schema_version`, `claim_id`, `session_id`, the
121
+ repository/worktree identities, canonical `resource`, `mode`, and timestamps.
122
+ The initial claim schema version is `1` and supports `read`, `write`, and
123
+ `exclusive-write`.
124
+
125
+ ```bash
126
+ git nawabari session claim --session "$NAWABARI_SESSION_ID" \
127
+ --resource 'src/**/*.ts' --mode read --json
128
+ git nawabari session claims --session "$NAWABARI_SESSION_ID" --json
129
+ git nawabari session update --session "$NAWABARI_SESSION_ID" \
130
+ --resource 'src/**/*.ts' --mode write --json
131
+ git nawabari session release --session "$NAWABARI_SESSION_ID" --json
132
+ ```
133
+
134
+ Overlapping claims use this complete compatibility matrix; non-overlapping
135
+ claims are compatible for every mode:
136
+
137
+ | existing \/ requested | read | write | exclusive-write |
138
+ | --------------------- | ---------- | -------- | --------------- |
139
+ | read | compatible | conflict | conflict |
140
+ | write | conflict | conflict | conflict |
141
+ | exclusive-write | conflict | conflict | conflict |
142
+
143
+ Claims use canonical repository-relative POSIX paths. Literal path segments,
144
+ `*`/`?` segment wildcards, and a complete `**` segment are supported. Empty,
145
+ `.`/`..`, absolute, drive-relative, backslash, unsupported-glob, and
146
+ symlink-escaping forms are rejected with stable machine-readable codes.
147
+ Equivalent claim acquisition and release retries are idempotent. Closing or
148
+ garbage-collecting a session releases its claims; no separate claim registry
149
+ or claim lock exists. Claims describe ownership state only and do not provide
150
+ OS-level filesystem observation or a filesystem sandbox.
56
151
 
57
152
  ## Ownership guard
58
153
 
@@ -70,10 +165,11 @@ decision=$(git nawabari guard --session "$NAWABARI_SESSION_ID" --json) || {
70
165
 
71
166
  An allowed decision has `allowed: true` and `code: "ALLOWED"`. A denied
72
167
  decision has `allowed: false`, a stable code such as
73
- `WORKTREE_OWNED_BY_OTHER_SESSION`, `PROTECTED_WORKTREE`, or
74
- `OWNERSHIP_MISMATCH`, and a non-zero exit status. Detached, corrupt, missing,
75
- or conflicting state fails closed. The guard does not install hooks and does
76
- not prevent direct filesystem writes outside Nawabari.
168
+ `WORKTREE_OWNED_BY_OTHER_SESSION`, `PROTECTED_WORKTREE`, `DETACHED_HEAD`,
169
+ `WORKTREE_MISMATCH`, or `OWNERSHIP_MISMATCH`, and a non-zero exit status.
170
+ Detached, corrupt, missing, or conflicting state fails closed. The guard does
171
+ not install hooks and does not prevent direct filesystem writes outside
172
+ Nawabari.
77
173
 
78
174
  ## Orchestrator integration
79
175
 
@@ -95,6 +191,95 @@ The orchestrator owns scheduling, prompts, and worker lifetime; Nawabari owns
95
191
  only local session identity, worktree/branch ownership, and safe cleanup. No
96
192
  Mottainai, GitHub, `gh`, network, or agent-runtime dependency is required.
97
193
 
194
+ Mottainai is one optional caller of this contract, not a runtime dependency.
195
+ It may retain task semantics, scheduling, validation policy, Issue/PR
196
+ governance, and worker lifetime. It must pass concrete local declarations to
197
+ Nawabari and retain the returned JSON identities. Nawabari does not import or
198
+ execute Mottainai/GitHub workflow code, infer claims from task text, or create
199
+ a second registry/database.
200
+
201
+ ## Claim-aware operation authorization
202
+
203
+ `authorize` is the single decision surface for a governed local operation. Its
204
+ versioned vocabulary and required claim access are:
205
+
206
+ | operation | required access |
207
+ | ----------------- | ----------------- |
208
+ | `source-write` | `write` |
209
+ | `stage` | `write` |
210
+ | `commit` | `exclusive-write` |
211
+ | `branch-mutation` | `exclusive-write` |
212
+ | `push` | `exclusive-write` |
213
+ | `cleanup` | `exclusive-write` |
214
+
215
+ The request contains a session identity, an operation, and concrete
216
+ repository-relative resources. Nawabari independently verifies the current
217
+ repository, owned worktree, branch, active session, and persisted claims;
218
+ caller-supplied labels do not weaken that decision. The JSON result is the
219
+ automation contract and reports stable allow/deny codes such as
220
+ `MISSING_RESOURCE_CLAIM`, `RESOURCE_CLAIM_CONFLICT`, `INVALID_RESOURCE`, and
221
+ the existing ownership/physical-observation codes.
222
+
223
+ **`authorize` returns an authorization decision only; it does NOT execute the
224
+ operation itself.** Governed commit and push execution use this same decision
225
+ path before invoking bounded Git subprocesses.
226
+
227
+ ```bash
228
+ git nawabari authorize --session "$NAWABARI_SESSION_ID" \
229
+ --operation source-write --resource src/example.ts --json
230
+ ```
231
+
232
+ Governed commit accepts only a caller-decided final message and explicit
233
+ repository-relative resources. Every resource must be covered by an active
234
+ `exclusive-write` claim; all Git-visible changed/staged paths must be in the
235
+ explicit list. JSON includes the resulting `commit_sha`.
236
+
237
+ ```bash
238
+ git nawabari commit --session "$NAWABARI_SESSION_ID" \
239
+ --message 'record the local change' --resource src/example.ts --json
240
+ ```
241
+
242
+ Governed push requires explicit claim-covered resources and an explicit
243
+ `--remote`/`--branch` target. Existing upstream and local/remote relation are
244
+ inspected before mutation. A missing upstream requires `--create-upstream`;
245
+ behind or diverged history requires explicit `--force`, which uses
246
+ `--force-with-lease`. The JSON result identifies the pushed `target` and
247
+ reports its relation.
248
+
249
+ ```bash
250
+ git nawabari push --session "$NAWABARI_SESSION_ID" \
251
+ --remote origin --branch feature/example --resource src/example.ts --json
252
+ ```
253
+
254
+ `checkpoint --json` captures bounded Git-observable `changed`, `staged`,
255
+ `unstaged`, and `untracked` path sets, canonicalizes them through the same
256
+ resource model, and reports `in_claim` and `out_of_claim` paths. Checkpoint
257
+ evidence is limited to the state Git exposes at that instant. Direct
258
+ filesystem activity that is reverted, ignored, or otherwise not observable in
259
+ the Git checkpoint is outside Nawabari's guarantee; this feature is not an
260
+ OS-level filesystem monitor.
261
+
262
+ ## Physical execution context
263
+
264
+ Nawabari treats Git and the canonical filesystem as the authority for every
265
+ governed session context. It independently observes the repository common
266
+ directory, worktree path, current branch, and current `HEAD`, then compares
267
+ those observations with the session registry. Caller-supplied paths and branch
268
+ labels are expectations only; they are never used to replace an observation
269
+ Git can make.
270
+
271
+ The shared verifier fails closed with stable registry reasons for detached
272
+ `HEAD`, missing or prunable worktrees, repository/worktree/branch mismatches,
273
+ stale or conflicting registry ownership, ambiguous Git state, and unavailable
274
+ physical observations. Git process failures remain distinct and bounded:
275
+ spawn failure, timeout, output-limit, and non-zero/unexpected exit.
276
+
277
+ Provisioning canonicalizes the managed root and every existing path segment
278
+ before invoking Git. Traversal, symlink/intermediate-segment escapes, existing
279
+ worktree paths, and existing local branches are rejected deterministically;
280
+ the repository lock serializes Nawabari provisioning and Git's own ref checks
281
+ remain the final collision authority.
282
+
98
283
  ## Repository state and concurrency
99
284
 
100
285
  The authoritative registry is stored in the repository-common Git directory at
@@ -110,6 +295,29 @@ owner is reclaimed only when the same host proves that exact process identity
110
295
  is dead. Invalid, remote, or otherwise unverifiable lock metadata is never
111
296
  stolen and fails closed so an operator can inspect or remove it deliberately.
112
297
 
298
+ ### Conformance and extraction boundary
299
+
300
+ The packed-package suite exercises the complete standalone sequence, including
301
+ cross-process claim conflicts, governed commit/push, reconciliation, retryable
302
+ cleanup, and prunable worktree recovery. Native tests additionally cover
303
+ process interruption/atomic-write recovery, partial staging or commit failure,
304
+ stale physical state, cleanup races, bounded subprocess failures, and
305
+ idempotency (`src/registry/store.test.ts`, `src/git-mutation.test.ts`,
306
+ `src/cleanup-authority.test.ts`, `src/session-lifecycle.test.ts`, and
307
+ `scripts/smoke-test.mjs`).
308
+
309
+ The relevant Mottainai #28 execution cases are mapped as follows:
310
+
311
+ - repository/worktree identity, provisioning path safety, branch collision,
312
+ symlink escape, local staging/commit/push safety, cleanup revalidation, and
313
+ reconciliation are Nawabari-native authority and tests;
314
+ - task semantics, prompts, validation evidence policy, Conventional Commit and
315
+ PR/Issue governance, GitHub operations, and agent hooks remain optional
316
+ orchestrator-only semantics and must not move into Nawabari.
317
+
318
+ Run `pnpm run test:package` to validate the exact packed tarball and its
319
+ installed CLI, or `pnpm run verify` for the complete local conformance gate.
320
+
113
321
  ## Development
114
322
 
115
323
  ```bash