acstack 0.52.4 → 0.52.6
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/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/cli/package.json +1 -1
- package/hooks/session-start.sh +4 -1
- package/orchestrator/AGENTS.md +59 -6
- package/package.json +1 -1
- package/pi/extension.ts +28 -8
- package/skills/teardown-worktree/SKILL.md +26 -24
- package/skills/teardown-worktree/artifacts.md +82 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "acstack",
|
|
3
3
|
"description": "Agentic coding stack where planning grows only as far as needed: a map of decisions, tasks, checks, and handoffs behind a pluggable tracker.",
|
|
4
|
-
"version": "0.52.
|
|
4
|
+
"version": "0.52.6",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "ac8318740"
|
|
7
7
|
},
|
package/README.md
CHANGED
|
@@ -284,7 +284,7 @@ What an effort leaves behind is what matters: updated specs, decision notes, and
|
|
|
284
284
|
| `/acstack:bridge` | Set up and operate the Playwriter cross-device browser bridge |
|
|
285
285
|
| `/acstack:visual-docs` | Write docs that lead with a diagram and derive structure from it (Minto pyramid) |
|
|
286
286
|
| `/acstack:new-worktree` | Create a git worktree off the remote base branch and continue the task inside it |
|
|
287
|
-
| `/acstack:teardown-worktree` | Retire finished worktrees
|
|
287
|
+
| `/acstack:teardown-worktree` | Retire finished worktrees, delete their merged local and remote branches, and clean build outputs in worktrees that stay |
|
|
288
288
|
| `/acstack:terminal-workspace` | Set up a keyboard-only terminal for driving agents on a dev machine |
|
|
289
289
|
|
|
290
290
|
## 6. Every agent
|
package/cli/package.json
CHANGED
package/hooks/session-start.sh
CHANGED
|
@@ -206,10 +206,13 @@ if ! command -v python3 >/dev/null 2>&1; then
|
|
|
206
206
|
fi
|
|
207
207
|
|
|
208
208
|
python3 - "$claude_md" <<'PY'
|
|
209
|
-
import json, sys
|
|
209
|
+
import json, re, sys
|
|
210
210
|
path = sys.argv[1]
|
|
211
211
|
with open(path, 'r', encoding='utf-8') as f:
|
|
212
212
|
content = f.read()
|
|
213
|
+
# SessionStart reaches the lead session, so it keeps the lead block and drops the delegated one.
|
|
214
|
+
content = re.sub(r'<!-- acstack:delegated:start -->[\s\S]*?<!-- acstack:delegated:end -->\n?', '', content)
|
|
215
|
+
content = re.sub(r'<!-- acstack:lead:(start|end) -->\n?', '', content)
|
|
213
216
|
print(json.dumps({
|
|
214
217
|
"hookSpecificOutput": {
|
|
215
218
|
"hookEventName": "SessionStart",
|
package/orchestrator/AGENTS.md
CHANGED
|
@@ -2,13 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
ACStack keeps meaningful tests and chooses verification effort to fit the change.
|
|
4
4
|
|
|
5
|
+
<!-- acstack:lead:start -->
|
|
5
6
|
## Your role
|
|
6
7
|
|
|
7
8
|
- Understand the request, investigate the code, implement, and verify the result
|
|
8
9
|
- Work directly on straightforward tasks, including research, tests, code, and checks
|
|
9
|
-
- Delegate when another agent materially improves confidence
|
|
10
|
+
- Delegate when another agent materially improves confidence, handles an independent scope, or keeps broad discovery out of your context
|
|
10
11
|
- Honor explicit user requests for stronger process, including separate agents and tests-first work
|
|
11
12
|
- Follow the shared Implementation discipline below across implement, quick-fix, and map work
|
|
13
|
+
- Keep the user's session continuous
|
|
14
|
+
- Use `/acstack:handoff` to transfer work to a visible agent
|
|
15
|
+
- Use `/acstack:compact-and-continue` to preserve session state before compaction
|
|
16
|
+
<!-- acstack:lead:end -->
|
|
17
|
+
<!-- acstack:delegated:start -->
|
|
18
|
+
## Your role
|
|
19
|
+
|
|
20
|
+
- You are a delegated session: the brief your parent gave at launch sets your role, scope, and access
|
|
21
|
+
- You may be an investigator, an implementer, or a coordinator of your own scope
|
|
22
|
+
- The shared guidance below applies wherever the brief does not narrow it
|
|
23
|
+
- Stay inside the assigned scope and access
|
|
24
|
+
- Report work outside them to your parent instead of doing it
|
|
25
|
+
- Treat a no-edit instruction as binding even when the launcher does not enforce it
|
|
26
|
+
- Delegate further only when the brief allows it, and never grant a child more access than you have
|
|
27
|
+
- Report results, evidence, and blockers to your parent
|
|
28
|
+
- Your parent owns synthesis and completion unless the brief assigns them to you
|
|
29
|
+
<!-- acstack:delegated:end -->
|
|
12
30
|
|
|
13
31
|
## Non-negotiable rules
|
|
14
32
|
|
|
@@ -40,12 +58,15 @@ ACStack runs on Claude Code, Codex, and pi. The skills name each capability once
|
|
|
40
58
|
|
|
41
59
|
- **Launch a subagent** – start a child agent with its own context, by its ACStack name (`test-writer`, `task-executor`, `task-checker`, `frontend-verifier`)
|
|
42
60
|
- Claude Code: the Agent tool, with `subagent_type` set to that name
|
|
43
|
-
- pi: `Agent` from `@tintinweb/pi-subagents` (`subagent_type`),
|
|
61
|
+
- pi: `Agent` from `@tintinweb/pi-subagents` (`subagent_type`), `subagent` from `pi-subagents` (`agent`), or `team_agent` from ac-teams
|
|
62
|
+
- `team_agent` does not load ACStack agents by name, so put the role's instructions in the brief
|
|
63
|
+
- ac-teams describes its member access controls in its own `docs/access.md`
|
|
44
64
|
- **Read-only codebase-search subagent** – `Explore` on Claude Code and pi's `Agent`, or `scout` on pi's `subagent`
|
|
45
65
|
- `debugger` names a debugging agent
|
|
46
66
|
- On a host without a matching built-in agent, launch a general subagent with that brief
|
|
47
67
|
- **Agent team** – parallel full sessions, each owning one scope and launching its own subagents
|
|
48
68
|
- Claude Code has agent teams, with messaging between teammates and plan approval by the lead
|
|
69
|
+
- pi has ac-teams, through `team_agent`
|
|
49
70
|
- On a host without agent teams, work directly or delegate scopes sequentially
|
|
50
71
|
- When the task assigns separate test ownership, keep it separate from implementation
|
|
51
72
|
- **Ask the user a structured question** – the host's question tool (AskUserQuestion on Claude Code)
|
|
@@ -215,6 +236,40 @@ flowchart TD
|
|
|
215
236
|
- Check the design gate and load design context once per task when it is on
|
|
216
237
|
- Follow the same procedure for direct work and delegated implementation
|
|
217
238
|
|
|
239
|
+
### Delegate investigation
|
|
240
|
+
|
|
241
|
+
- Prefer delegated investigation when discovery means broad searches, substantial reading, independent hypotheses, or separable research questions
|
|
242
|
+
- Delegation keeps raw discovery out of your context, even when the investigator runs your own model
|
|
243
|
+
- Work directly when the paths are few and known, or when briefing costs more than searching
|
|
244
|
+
- Launch one investigator per separable question, with no fixed count
|
|
245
|
+
- Launch the host's read-only search agent for navigation questions (see Host tools)
|
|
246
|
+
- For other questions, launch a general agent with the investigator brief below
|
|
247
|
+
- With no launcher available, investigate directly and say that delegation was unavailable
|
|
248
|
+
- Choose the model separately from the role
|
|
249
|
+
- Prefer a configured cheaper, capable model for navigation and fact gathering
|
|
250
|
+
- Use a stronger model for hard causal or ambiguous analysis
|
|
251
|
+
- Never hardcode a provider or model; use what the host or user configured
|
|
252
|
+
- Request enforced read-only access when the launcher reports that it can enforce it
|
|
253
|
+
- Expect prompt-only protection on most hosts today
|
|
254
|
+
- A read-only search agent such as `Explore` lacks edit tools; that limits its tools but is not operating-system enforcement
|
|
255
|
+
- Without enforcement, instruct the investigator not to edit project files, and call that protection prompt-only
|
|
256
|
+
- If an enforced launch fails, report the failure and ask before launching without enforcement
|
|
257
|
+
- Own the synthesis: verify the decisive evidence a conclusion rests on, without repeating the whole investigation
|
|
258
|
+
|
|
259
|
+
The investigator brief states:
|
|
260
|
+
|
|
261
|
+
- The question, and why the answer matters
|
|
262
|
+
- The scope: paths, repositories, or sources to search, and what is out of scope
|
|
263
|
+
- The access: enforced read-only, or a prompt-only instruction not to edit project files
|
|
264
|
+
- The report the parent needs back
|
|
265
|
+
|
|
266
|
+
The investigator reports:
|
|
267
|
+
|
|
268
|
+
- Findings, with file paths and line references
|
|
269
|
+
- Which findings rest on evidence and which are hypotheses
|
|
270
|
+
- What it searched, so the parent knows what it did not cover
|
|
271
|
+
- Uncertainties, and the next checks worth running
|
|
272
|
+
|
|
218
273
|
### Use independent review where needed
|
|
219
274
|
|
|
220
275
|
- Require independent review for security boundaries, money, irreversible data changes, or unresolved correctness or impact uncertainty
|
|
@@ -414,8 +469,8 @@ Launch each agent by the name below (see Host tools for how your host takes it).
|
|
|
414
469
|
| Implement task | `task-executor` | Source and tests unless tests have a separate owner |
|
|
415
470
|
| Verify implementation | `task-checker` | Independent review, coverage adequacy, regressions |
|
|
416
471
|
| Verify frontend UI | `frontend-verifier` | Real browser, screenshots, non-negotiable |
|
|
417
|
-
|
|
|
418
|
-
| Debug
|
|
472
|
+
| Investigate a question | `Explore` / `scout`, or a general agent | Read-only; brief per Delegate investigation |
|
|
473
|
+
| Debug | `debugger` | Built-in debugging agent |
|
|
419
474
|
|
|
420
475
|
---
|
|
421
476
|
|
|
@@ -436,5 +491,3 @@ Launch each agent by the name below (see Host tools for how your host takes it).
|
|
|
436
491
|
- Keep living specs current through commit-time sync
|
|
437
492
|
- Create a map when unresolved questions need durable tracking
|
|
438
493
|
- Invoke `bridge` before cross-device browser or tunnel work
|
|
439
|
-
- Use `/acstack:handoff` to transfer work to a visible agent
|
|
440
|
-
- Use `/acstack:compact-and-continue` to preserve session state before compaction
|
package/package.json
CHANGED
package/pi/extension.ts
CHANGED
|
@@ -80,6 +80,8 @@ function ensureProjectData(ctx: ExtensionContext, root: string): boolean {
|
|
|
80
80
|
const SUBAGENT_CHILD_ENV = "PI_SUBAGENT_CHILD";
|
|
81
81
|
/** pi-subagents sets this instead in a child it places in its own herdr pane. */
|
|
82
82
|
const HERDR_BRIDGE_CHILD_ENV = "PI_SUBAGENTS_HERDR_BRIDGE";
|
|
83
|
+
/** ac-teams sets this in every member it launches. */
|
|
84
|
+
const AC_TEAMS_MEMBER_ENV = "AC_TEAMS_MEMBER";
|
|
83
85
|
|
|
84
86
|
function agentDir(): string {
|
|
85
87
|
return process.env.PI_CODING_AGENT_DIR || path.join(os.homedir(), ".pi", "agent");
|
|
@@ -622,6 +624,18 @@ export function skillsSection(skills: Map<string, SkillInfo>): string | undefine
|
|
|
622
624
|
return lines.join("\n");
|
|
623
625
|
}
|
|
624
626
|
|
|
627
|
+
/**
|
|
628
|
+
* The orchestrator text for one kind of session. orchestrator/AGENTS.md marks
|
|
629
|
+
* the lead-only and delegated-only blocks; each session keeps its own block
|
|
630
|
+
* and drops the other.
|
|
631
|
+
*/
|
|
632
|
+
export function orchestratorFor(text: string, role: "lead" | "delegated"): string {
|
|
633
|
+
const other = role === "lead" ? "delegated" : "lead";
|
|
634
|
+
return text
|
|
635
|
+
.replace(new RegExp(`<!-- acstack:${other}:start -->[\\s\\S]*?<!-- acstack:${other}:end -->\\n?`, "g"), "")
|
|
636
|
+
.replace(new RegExp(`<!-- acstack:${role}:(start|end) -->\\n?`, "g"), "");
|
|
637
|
+
}
|
|
638
|
+
|
|
625
639
|
/**
|
|
626
640
|
* The user message for one ACStack skill, in the same shape pi's own
|
|
627
641
|
* /skill:<name> expansion produces. Built from this package's file, so a
|
|
@@ -640,9 +654,9 @@ export function skillInvocation(name: string, file: string, args: string): strin
|
|
|
640
654
|
// --------------------------------------------------------------------------
|
|
641
655
|
|
|
642
656
|
export default function acstack(pi: ExtensionAPI): void {
|
|
643
|
-
// A
|
|
644
|
-
//
|
|
645
|
-
|
|
657
|
+
// A delegated session keeps the shared guidance but not the lead's role,
|
|
658
|
+
// CLI symlinks, launcher warning, context nudges, or handoff reload.
|
|
659
|
+
const delegated = process.env[SUBAGENT_CHILD_ENV] === "1" || process.env[HERDR_BRIDGE_CHILD_ENV] === "1" || Boolean(process.env[AC_TEAMS_MEMBER_ENV]);
|
|
646
660
|
|
|
647
661
|
const orchestratorFile = path.join(packageRoot, "orchestrator", "AGENTS.md");
|
|
648
662
|
const styleFile = path.join(packageRoot, "output-styles", "ac-writing-style.md");
|
|
@@ -651,7 +665,7 @@ export default function acstack(pi: ExtensionAPI): void {
|
|
|
651
665
|
let warnedSubagents = false;
|
|
652
666
|
|
|
653
667
|
pi.on("session_start", async (event, ctx) => {
|
|
654
|
-
linkClis(ctx);
|
|
668
|
+
if (!delegated) linkClis(ctx);
|
|
655
669
|
const root = projectRoot(ctx.cwd);
|
|
656
670
|
if (ensureProjectData(ctx, root)) unsafeProjects.delete(root);
|
|
657
671
|
else {
|
|
@@ -659,6 +673,7 @@ export default function acstack(pi: ExtensionAPI): void {
|
|
|
659
673
|
return;
|
|
660
674
|
}
|
|
661
675
|
|
|
676
|
+
if (delegated) return;
|
|
662
677
|
if (!warnedSubagents && !pi.getAllTools().some((tool) => tool.name === "subagent" || tool.name === "Agent" || tool.name === "team_agent")) {
|
|
663
678
|
warnedSubagents = true;
|
|
664
679
|
report(
|
|
@@ -686,14 +701,19 @@ export default function acstack(pi: ExtensionAPI): void {
|
|
|
686
701
|
|
|
687
702
|
if (isProject(ctx.cwd)) {
|
|
688
703
|
const orchestrator = readText(orchestratorFile);
|
|
689
|
-
if (orchestrator) sections["acstack-orchestrator"] = orchestrator;
|
|
704
|
+
if (orchestrator) sections["acstack-orchestrator"] = orchestratorFor(orchestrator, delegated ? "delegated" : "lead");
|
|
690
705
|
else report(ctx, `acstack: could not read ${orchestratorFile}`, "warning");
|
|
691
706
|
}
|
|
692
707
|
|
|
693
708
|
const styleCfg = writingStyleSettings();
|
|
694
709
|
if (styleCfg.mode === "off") return;
|
|
695
710
|
const resolvedStyleFile = styleCfg.mode === "custom" && styleCfg.path ? expandUserPath(styleCfg.path) : styleFile;
|
|
696
|
-
|
|
711
|
+
let style = readText(resolvedStyleFile);
|
|
712
|
+
// A sandboxed delegated session may not see a custom file outside its read roots.
|
|
713
|
+
if (!style && delegated && resolvedStyleFile !== styleFile) {
|
|
714
|
+
report(ctx, `acstack: could not read writing style at ${resolvedStyleFile}; using the bundled style`, "warning");
|
|
715
|
+
style = readText(styleFile);
|
|
716
|
+
}
|
|
697
717
|
if (!style) {
|
|
698
718
|
report(ctx, `acstack: could not read writing style at ${resolvedStyleFile}`, "warning");
|
|
699
719
|
return;
|
|
@@ -705,7 +725,7 @@ export default function acstack(pi: ExtensionAPI): void {
|
|
|
705
725
|
return { message: { customType: "acstack-writing-style-reminder", content: reminder, display: false } };
|
|
706
726
|
});
|
|
707
727
|
|
|
708
|
-
pi.on("agent_before_settle", async (event, ctx) => {
|
|
728
|
+
if (!delegated) pi.on("agent_before_settle", async (event, ctx) => {
|
|
709
729
|
if (event.outcome !== "completed") return;
|
|
710
730
|
const usage = ctx.getContextUsage();
|
|
711
731
|
if (!usage || usage.tokens === null) return;
|
|
@@ -736,7 +756,7 @@ export default function acstack(pi: ExtensionAPI): void {
|
|
|
736
756
|
};
|
|
737
757
|
});
|
|
738
758
|
|
|
739
|
-
pi.on("session_compact", async (_event, ctx) => {
|
|
759
|
+
if (!delegated) pi.on("session_compact", async (_event, ctx) => {
|
|
740
760
|
// The compaction threw the old context away, so the ladder starts over.
|
|
741
761
|
const key = sessionKey(ctx);
|
|
742
762
|
if (key) {
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: teardown-worktree
|
|
3
|
-
description: "Retire finished git worktrees – move this session back to the main checkout, move the orchestrator's pane back to the main repo workspace, remove the checkouts,
|
|
3
|
+
description: "Retire finished git worktrees – move this session back to the main checkout, move the orchestrator's pane back to the main repo workspace, remove the checkouts, delete the merged local and remote branches, and offer to clean rebuildable build outputs in worktrees that stay. Scans the whole repo, not just the current worktree. Use whenever the user says \"tear down the worktree\", \"clean up worktrees\", \"remove this worktree\", \"delete the worktree and branch\", \"clean up stale worktrees\", \"free disk space from old sessions\", or otherwise wants finished worktrees and their branches gone."
|
|
4
4
|
argument-hint: "[worktree name, or nothing to scan the whole repo]"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Teardown worktree
|
|
8
8
|
|
|
9
|
-
Retire finished worktrees.
|
|
10
|
-
|
|
11
|
-
Move this session out first. Remove the worktrees next. Delete the branches they were on last.
|
|
9
|
+
Retire finished worktrees. Move this session out first. Remove the worktrees next. Delete the branches they were on last.
|
|
12
10
|
|
|
13
11
|
Removing a worktree this session is standing in, or one that still holds a running agent, destroys live work. The order below exists to prevent that, as far as either orchestrator can tell. Follow it.
|
|
14
12
|
|
|
@@ -24,9 +22,7 @@ One repo per run: the repo that owns the cwd. Resolve its main checkout from any
|
|
|
24
22
|
dirname "$(git rev-parse --git-common-dir)"
|
|
25
23
|
```
|
|
26
24
|
|
|
27
|
-
Submodules are separate repos with their own worktrees and their own remote.
|
|
28
|
-
|
|
29
|
-
If the repo has submodules carrying worktrees, say so. Offer a second run against each. Never scan them silently.
|
|
25
|
+
Submodules are separate repos with their own worktrees and their own remote. If the repo has submodules carrying worktrees, say so. Offer a second run against each. Never scan them silently.
|
|
30
26
|
|
|
31
27
|
## 1. Build the plan
|
|
32
28
|
|
|
@@ -38,11 +34,11 @@ List every worktree of the repo:
|
|
|
38
34
|
git worktree list --porcelain
|
|
39
35
|
```
|
|
40
36
|
|
|
41
|
-
Skip the main checkout. First settle who hosts this session and who owns each checkout, then classify each remaining worktree on the
|
|
37
|
+
Skip the main checkout. First settle who hosts this session and who owns each checkout, then classify each remaining worktree on the five checks that follow.
|
|
42
38
|
|
|
43
39
|
### Which orchestrator hosts this session, and which one owns each checkout
|
|
44
40
|
|
|
45
|
-
Settle both before the
|
|
41
|
+
Settle both before the five checks. A worktree orchestrator is a tool that opens panes and holds worktrees for you – herdr and Orca are the two this skill knows.
|
|
46
42
|
|
|
47
43
|
Two different facts drive this skill:
|
|
48
44
|
|
|
@@ -95,9 +91,11 @@ git -C <path> status --porcelain --ignore-submodules=all
|
|
|
95
91
|
|
|
96
92
|
Report pointer drift in the plan anyway, from `git -C <path> submodule status`. That way a real pending bump stays visible, and the ignore flag does not hide it.
|
|
97
93
|
|
|
98
|
-
Any output from the status check means skip.
|
|
94
|
+
Any output from the status check means skip. Do not remove it. Do not force it. List it at the end with what it holds.
|
|
95
|
+
|
|
96
|
+
### Ignored data
|
|
99
97
|
|
|
100
|
-
|
|
98
|
+
Removal deletes every file git ignores, forced or not, and the status check cannot see them. Follow `artifacts.md` step 1. Any preserve path, such as `.env` or Terraform state, means skip unless the user approves losing that named path.
|
|
101
99
|
|
|
102
100
|
### Merged
|
|
103
101
|
|
|
@@ -135,7 +133,9 @@ Nothing holds agent state, so nothing can confirm liveness. Classification then
|
|
|
135
133
|
|
|
136
134
|
### Show it
|
|
137
135
|
|
|
138
|
-
Print one table with
|
|
136
|
+
Print one table with seven columns: worktree, branch, whether the local branch goes, whether the remote branch goes, blocking panes, ignored data (each preserve path with its size, then the rebuildable total), and the reason.
|
|
137
|
+
|
|
138
|
+
Below the table, list the build outputs step 5 could clean in worktrees that stay. Then ask once: the user approves the removals and picks which cleans to run.
|
|
139
139
|
|
|
140
140
|
The blocking panes column names each pane that blocks the removal, pane id first and process name after – `w26:p2 claude` for example. Leave the cell empty when nothing blocks. The user then knows which pane to close.
|
|
141
141
|
|
|
@@ -147,9 +147,7 @@ Do this before removing anything, and only after approval.
|
|
|
147
147
|
|
|
148
148
|
So no tool call walks the session cwd back. `ExitWorktree` only unwinds a worktree this session entered with `EnterWorktree`. It is a no-op for a session that launched inside one.
|
|
149
149
|
|
|
150
|
-
The removal itself is what moves the session. Run it from the main checkout against an absolute path.
|
|
151
|
-
|
|
152
|
-
The harness then resets the session cwd to the main checkout on its own. Confirm with `pwd` afterwards.
|
|
150
|
+
The removal itself is what moves the session. Run it from the main checkout against an absolute path. The harness then resets the session cwd to the main checkout on its own. Confirm with `pwd` afterwards.
|
|
153
151
|
|
|
154
152
|
- Entered with `EnterWorktree`: call `ExitWorktree` with `action: "keep"` first. Keep, not remove: step 3 owns the removal, and `remove` refuses on a worktree entered by path.
|
|
155
153
|
- Launched inside the worktree: no call needed.
|
|
@@ -158,9 +156,7 @@ The harness then resets the session cwd to the main checkout on its own. Confirm
|
|
|
158
156
|
|
|
159
157
|
That much is the same everywhere. What follows depends on the branch `active` names. This step is the one place `active` still decides anything: how this session moves itself.
|
|
160
158
|
|
|
161
|
-
When `active` is `herdr`, follow `herdr.md` step 2 before you remove anything.
|
|
162
|
-
|
|
163
|
-
When `active` is `orca`, follow `orca.md` step 2. It leaves this session's own checkout in place.
|
|
159
|
+
When `active` is `herdr`, follow `herdr.md` step 2 before you remove anything. When `active` is `orca`, follow `orca.md` step 2. It leaves this session's own checkout in place.
|
|
164
160
|
|
|
165
161
|
### Host: none
|
|
166
162
|
|
|
@@ -172,11 +168,9 @@ Every removal through herdr or plain git passes `--force`. Orca is the exception
|
|
|
172
168
|
|
|
173
169
|
Plain `git worktree remove` refuses on any worktree containing submodules with "working trees containing submodules cannot be moved or removed". That refusal hits every worktree in a repo that has them.
|
|
174
170
|
|
|
175
|
-
Forcing is safe only because step 1 already proved the tree clean. It is never a way past uncommitted changes.
|
|
176
|
-
|
|
177
|
-
The hard rule: never run `worktree remove --force` on a workspace that still holds a pane other than this session's own. Forcing waives herdr's own check, so the pane enumeration is the only guard left.
|
|
171
|
+
Forcing is safe only because step 1 already proved the tree clean and its ignored data rebuildable or approved for loss. It is never a way past uncommitted changes.
|
|
178
172
|
|
|
179
|
-
Enumerate the panes again immediately before the call. Refuse the removal while any other pane remains.
|
|
173
|
+
The hard rule: never run `worktree remove --force` on a workspace that still holds a pane other than this session's own. Forcing waives herdr's own check, so the pane enumeration is the only guard left. Enumerate the panes again immediately before the call. Refuse the removal while any other pane remains.
|
|
180
174
|
|
|
181
175
|
Take the branch each checkout's `owner` names, not the branch `active` names. Decide per worktree: one checkout in the plan can belong to herdr while the next is plain git.
|
|
182
176
|
|
|
@@ -210,12 +204,17 @@ Use `branch -d`, never `-D`. If `-d` refuses, the merge test was wrong. Stop and
|
|
|
210
204
|
|
|
211
205
|
Skip the remote delete when nobody ever pushed the branch, or when merging the pull request already deleted it. The `git fetch origin --prune` from step 1 keeps a branch GitHub already removed from looking like work to do.
|
|
212
206
|
|
|
213
|
-
## 5.
|
|
207
|
+
## 5. Clean build outputs in kept worktrees
|
|
208
|
+
|
|
209
|
+
Only for worktrees that stay, whether step 1 skipped them or step 3 kept them, and only for the paths the user picked. Follow `artifacts.md` step 5. This step never retires a worktree, stops an agent, or closes a workspace.
|
|
210
|
+
|
|
211
|
+
## 6. Report
|
|
214
212
|
|
|
215
213
|
State what went and what stayed:
|
|
216
214
|
|
|
217
215
|
- Worktrees removed, with their branches
|
|
218
|
-
-
|
|
216
|
+
- Build outputs cleaned, with the space each freed, and the ones left because something was running
|
|
217
|
+
- Worktrees skipped, each with its reason: uncommitted work, preserve data it holds, an unmerged branch, a live agent or terminal, or the checkout this Orca terminal stands in
|
|
219
218
|
- Which live-agent checks ran against each worktree, and which did not, so nobody reads a missing check as a passed check
|
|
220
219
|
- Anything left for the user to decide
|
|
221
220
|
|
|
@@ -228,6 +227,9 @@ State what went and what stayed:
|
|
|
228
227
|
- Remove a workspace that still holds a pane other than your own.
|
|
229
228
|
- Reach for `EnterWorktree` to get back to the main checkout. It rejects the main working tree.
|
|
230
229
|
- Force past uncommitted changes. Skip and report instead.
|
|
230
|
+
- Read a clean status as proof the checkout holds nothing. It hides ignored files, and removal deletes them.
|
|
231
|
+
- Clean build outputs in a worktree with a live agent or process. Report the size instead.
|
|
232
|
+
- Remove a worktree, stop an agent, or delete a Docker volume only to reclaim disk space.
|
|
231
233
|
- Reach for `git branch -D` when `-d` refuses.
|
|
232
234
|
- Call a branch unmerged on the ancestor check alone. Check the pull request before deciding.
|
|
233
235
|
- Delete a remote branch with no merged pull request and no ancestor in an integration branch.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Teardown worktree: ignored data and build outputs
|
|
2
|
+
|
|
3
|
+
What to do with the files git ignores. `SKILL.md` step 1 lists them, and step 5 cleans build outputs in worktrees that stay. Each section names the step it belongs to.
|
|
4
|
+
|
|
5
|
+
## Why ignored data needs its own check
|
|
6
|
+
|
|
7
|
+
`git worktree remove` deletes every ignored file in the checkout, with or without `--force`, and says nothing. The uncommitted-work check cannot see them, because `git status` hides ignored paths.
|
|
8
|
+
|
|
9
|
+
Ignored does not mean disposable. `.env`, local databases, Terraform state, backups, notebooks, and review or design output are often ignored precisely because they are local and unique. Clean, merged, idle, and done are not proof either.
|
|
10
|
+
|
|
11
|
+
## Step 1 – list and classify
|
|
12
|
+
|
|
13
|
+
List the ignored paths, collapsed to directories, with their sizes:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
git -C <path> ls-files --others --ignored --exclude-standard --directory -z \
|
|
17
|
+
| xargs -0 -r -I{} du -sh -- "<path>/{}"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Class each path as one of two things:
|
|
21
|
+
|
|
22
|
+
- **Rebuildable**: a tool-native command regenerates it from tracked files. The table below gives the common cases. Each one needs the tracked manifest or lockfile it names to exist in the checkout.
|
|
23
|
+
- **Preserve**: everything else. A generated-looking name or extension alone is not evidence. When unsure, preserve.
|
|
24
|
+
|
|
25
|
+
| Path | Rebuilt by | Needs tracked | Native clean |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| Cargo `target/` | `cargo build` | `Cargo.toml` | `cargo clean --manifest-path <path>/Cargo.toml` |
|
|
28
|
+
| `node_modules/` | `npm ci`, `pnpm install`, `yarn install` | the lockfile | `rm -rf <path>/node_modules` |
|
|
29
|
+
| `.next/`, `dist/`, `build/` | the project's build script | `package.json` naming that output | the project's `clean` script, or `rm -rf` the directory |
|
|
30
|
+
| `.terraform/providers/` | `terraform init` | `.terraform.lock.hcl` | `rm -rf <path>/.terraform/providers` |
|
|
31
|
+
| `__pycache__/`, `.pytest_cache/`, `.mypy_cache/`, `.ruff_cache/` | the next run | nothing | `rm -rf` the directory |
|
|
32
|
+
|
|
33
|
+
The listing collapses a wholly ignored directory to one line. Class that line by everything inside it, and list inside any directory that can mix the two classes:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
du -sh -- <path>/.terraform/*
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Only the `providers/` directory under `.terraform/` is rebuildable. The rest of `.terraform/`, `*.tfstate`, and `*.tfstate.backup` are state. Preserve them.
|
|
40
|
+
|
|
41
|
+
A Python virtual environment is preserve by default, even with a tracked requirements file. Packages installed by hand do not show up in it. Call it rebuildable only when the user confirms.
|
|
42
|
+
|
|
43
|
+
Prefer the project's own clean script when `package.json`, a `Makefile`, or `justfile` defines one. Read what it deletes first.
|
|
44
|
+
|
|
45
|
+
### What the sizes do and do not say
|
|
46
|
+
|
|
47
|
+
`du` reports allocated size. Hardlinked stores, such as pnpm's, free less than that when removed. A symlink costs nothing, and removal deletes the link, never its target.
|
|
48
|
+
|
|
49
|
+
Shared caches outside the checkout, such as `~/.cargo`, `~/.npm`, and the pip cache, serve every project. They are out of scope. Never clean them from a teardown.
|
|
50
|
+
|
|
51
|
+
### Data outside the checkout
|
|
52
|
+
|
|
53
|
+
Removal leaves behind what the session created elsewhere. Report the parts you can find. Never delete them from a teardown:
|
|
54
|
+
|
|
55
|
+
- Docker Compose containers and their volumes, when Docker is installed:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
docker ps -a --filter "label=com.docker.compose.project.working_dir=<path>" --format '{{.Names}} {{.Status}}'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- A Cargo target directory moved out by `CARGO_TARGET_DIR` or `.cargo/config.toml`
|
|
62
|
+
|
|
63
|
+
## Step 1 – what it means for the plan
|
|
64
|
+
|
|
65
|
+
Removing a worktree deletes everything ignored in it, so:
|
|
66
|
+
|
|
67
|
+
- Every ignored path rebuildable: the worktree can go. List the paths and total size in the plan.
|
|
68
|
+
- Any preserve path: skip the worktree. Name each preserve path and its size, so the user can move or delete it deliberately.
|
|
69
|
+
|
|
70
|
+
The user can approve losing a named preserve path in the plan. Only an explicit approval naming that path counts. A general yes to the plan does not.
|
|
71
|
+
|
|
72
|
+
## Step 5 – clean build outputs in kept worktrees
|
|
73
|
+
|
|
74
|
+
A worktree can be skipped from retirement and still hold gigabytes of build output. Cleaning that output is a separate decision from removing the worktree. It never retires the worktree, stops an agent, or closes a workspace.
|
|
75
|
+
|
|
76
|
+
Offer it for each kept worktree whose rebuildable paths total more than about 100 MB. List the paths, sizes, and the native clean command for each. The user picks which to run.
|
|
77
|
+
|
|
78
|
+
Clean a path only when step 1's live-agent checks found nothing running in that worktree. A live agent, editor, dev server, or build may be using the output, so report the size instead and leave it.
|
|
79
|
+
|
|
80
|
+
Rerun the live-agent checks immediately before each clean. Even then, finding no process is a snapshot, not a lock. Something can start using the path a moment later. Say so in the report rather than calling the clean safe.
|
|
81
|
+
|
|
82
|
+
Run the native command from the table, against absolute paths. Never run `git clean -X` or `git clean -x`. Either one deletes every preserve path along with the build output.
|