aligndev 0.20.1 → 0.21.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.
@@ -1,6 +1,6 @@
1
1
  import { renderGuideTemplate } from "./render-template.js";
2
2
  export function renderCodeGuide(platform, agent, models, forms) {
3
- return renderGuideTemplate("code.md", platform, forms, {
3
+ return renderGuideTemplate("code.md", { platform }, forms, {
4
4
  AGENT: agent,
5
5
  AUTH_COMMAND: agent === "claude" ? "`claude`, then `/login`" : "`codex login`",
6
6
  PERMISSIONS: agent === "claude"
@@ -4,6 +4,7 @@ import { PLATFORMS, requireProjectsRoot, resolveCodeConfig, } from "../config.js
4
4
  import { errorMessage } from "../errors.js";
5
5
  import { renderProjectsGuideForRoot } from "../project/project-cli.js";
6
6
  import { renderCodeGuide } from "./code-guide.js";
7
+ import { resolveGuideFile } from "./guide-file.js";
7
8
  import { renderGuideTemplate } from "./render-template.js";
8
9
  import { PLAYBOOK_DISPATCHER, PLAYBOOK_TOPICS } from "./topics.js";
9
10
  export function runGuide(tokens, config, ctx) {
@@ -57,20 +58,24 @@ function renderTopic(args, config, ctx) {
57
58
  if (args.topic === "project" && config.platform === "openclaw") {
58
59
  return renderProjectsGuideForRoot({ ...ctx, projectsRoot: config.projectsRoot }, args.root);
59
60
  }
60
- return renderPlaybookTopic(args.topic, config, ctx.forms);
61
+ return renderPlaybookTopic(args.topic, config, ctx);
61
62
  }
62
63
  function renderCodeTopic(config, ctx) {
63
64
  const code = resolveCodeConfig(config, ctx.env);
64
65
  const models = resolveModels(code.agent, code.models);
65
66
  return renderCodeGuide(config.platform, code.agent, models, ctx.forms);
66
67
  }
67
- function renderPlaybookTopic(topic, config, forms) {
68
+ function renderPlaybookTopic(topic, config, ctx) {
68
69
  if (topic !== undefined)
69
70
  assertPlaybookTopic(topic, config.platform);
70
- const values = config.platform === "openclaw"
71
- ? { PROJECTS_ROOT: requireProjectsRoot(config).written }
72
- : undefined;
73
- return renderGuideTemplate(`playbook/${topic ?? PLAYBOOK_DISPATCHER}.md`, config.platform, forms, values);
71
+ const name = `playbook/${topic ?? PLAYBOOK_DISPATCHER}.md`;
72
+ if (config.platform === "codingAgent") {
73
+ const active = { platform: config.platform, guideFile: resolveGuideFile(ctx) };
74
+ return renderGuideTemplate(name, active, ctx.forms);
75
+ }
76
+ return renderGuideTemplate(name, { platform: config.platform }, ctx.forms, {
77
+ PROJECTS_ROOT: requireProjectsRoot(config).written,
78
+ });
74
79
  }
75
80
  function assertPlaybookTopic(topic, platform) {
76
81
  const topics = PLAYBOOK_TOPICS[platform];
@@ -0,0 +1,3 @@
1
+ import type { ProjectsCallerContext } from "../project/project-cli.js";
2
+ import type { GuideFileCondition } from "./render-template.js";
3
+ export declare function resolveGuideFile(ctx: ProjectsCallerContext): GuideFileCondition;
@@ -0,0 +1,26 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { readProjectReport } from "../project/layout.js";
5
+ // The project's guide file for the coding-agent assistant, resolved from PROJECT_PATH, the main
6
+ // worktree of the working directory: its `DEVELOPERS.md`, else its `README.md`, else none.
7
+ export function resolveGuideFile(ctx) {
8
+ const projectPath = mainWorktree(ctx);
9
+ if (projectPath === undefined)
10
+ return "noGuide";
11
+ const report = readProjectReport(ctx.alignfirstCommand, projectPath, ctx.env);
12
+ if ("error" in report)
13
+ throw new Error(report.error);
14
+ if (report.locations["DEVELOPERS.md"].exists)
15
+ return "developers";
16
+ return existsSync(join(projectPath, "README.md")) ? "readme" : "noGuide";
17
+ }
18
+ function mainWorktree(ctx) {
19
+ try {
20
+ const commonDir = execFileSync("git", ["-C", ctx.cwd, "rev-parse", "--path-format=absolute", "--git-common-dir"], { encoding: "utf8", env: ctx.env, stdio: ["ignore", "pipe", "ignore"] }).trim();
21
+ return dirname(commonDir);
22
+ }
23
+ catch {
24
+ return;
25
+ }
26
+ }
@@ -1,4 +1,11 @@
1
1
  import type { CommandForms } from "../command-form.js";
2
2
  import { type Platform } from "../config.js";
3
- export declare function renderGuideTemplate(name: string, platform: Platform, forms: CommandForms, values?: Readonly<Record<string, string>>): string;
4
- export declare function renderPlatformBlocks(text: string, platform: Platform, templateName: string): string;
3
+ declare const GUIDE_FILE_CONDITIONS: readonly ["developers", "readme", "noGuide"];
4
+ export type GuideFileCondition = (typeof GUIDE_FILE_CONDITIONS)[number];
5
+ export interface ActiveBlocks {
6
+ platform: Platform;
7
+ guideFile?: GuideFileCondition;
8
+ }
9
+ export declare function renderGuideTemplate(name: string, active: ActiveBlocks, forms: CommandForms, values?: Readonly<Record<string, string>>): string;
10
+ export declare function renderBlocks(text: string, active: ActiveBlocks, templateName: string): string;
11
+ export {};
@@ -1,59 +1,86 @@
1
1
  import { PLATFORMS } from "../config.js";
2
2
  import { readTemplate } from "../templates.js";
3
+ const GUIDE_FILE_CONDITIONS = ["developers", "readme", "noGuide"];
4
+ // Active for both guide files: `developers` and `readme`.
5
+ const HAS_GUIDE = "hasGuide";
3
6
  const MARKER = /^\{\{([#/])([A-Za-z]+)\}\}$/;
4
- // Renders `templates/guide/<name>`: the platform blocks first, then the placeholders — the command
5
- // forms and every key of `values`.
6
- export function renderGuideTemplate(name, platform, forms, values = {}) {
7
+ // Renders `templates/guide/<name>`: the blocks first, then the placeholders — the command forms
8
+ // and every key of `values`.
9
+ export function renderGuideTemplate(name, active, forms, values = {}) {
7
10
  const placeholders = {
8
11
  ALIGNDEV: forms.aligndev,
9
12
  ALIGNFIRST: forms.alignfirst,
10
13
  ...values,
11
14
  };
12
- let text = renderPlatformBlocks(readTemplate(`guide/${name}`), platform, name);
15
+ let text = renderBlocks(readTemplate(`guide/${name}`), active, name);
13
16
  for (const [key, value] of Object.entries(placeholders)) {
14
17
  text = text.replaceAll(`{{${key}}}`, value);
15
18
  }
16
19
  return text.trimEnd();
17
20
  }
18
- // A block is `{{#<platform>}}` … `{{/<platform>}}`, each marker alone on its line. The active
19
- // platform's blocks keep their content; the others are removed. Blocks do not nest. The runs of
20
- // empty lines that removed blocks leave collapse to one.
21
- export function renderPlatformBlocks(text, platform, templateName) {
21
+ // A block is `{{#<name>}}` … `{{/<name>}}`, each marker alone on its line. A platform block sits
22
+ // at the top level; a condition block sits directly inside a `codingAgent` block. A line
23
+ // is kept when every block around it is active. The runs of empty lines that removed blocks leave
24
+ // collapse to one.
25
+ export function renderBlocks(text, active, templateName) {
22
26
  const kept = [];
23
- let open;
27
+ const open = [];
24
28
  for (const [index, line] of text.split("\n").entries()) {
25
29
  const marker = MARKER.exec(line);
26
30
  if (marker === null) {
27
- if (open === undefined || open.platform === platform)
31
+ if (open.every((block) => isActive(block.name, active)))
28
32
  kept.push(line);
29
33
  continue;
30
34
  }
31
35
  const [, kind, name] = marker;
32
36
  const lineNumber = index + 1;
33
- if (!isPlatform(name)) {
34
- throw blockError(templateName, lineNumber, `unknown platform "${name}"`);
35
- }
36
- if (kind === "#") {
37
- if (open !== undefined) {
38
- throw blockError(templateName, lineNumber, `block "${name}" nested in "${open.platform}"`);
39
- }
40
- open = { platform: name, line: lineNumber };
37
+ if (kind === "#")
38
+ open.push(openBlock(name, lineNumber, open, templateName));
39
+ else
40
+ closeBlock(name, lineNumber, open, templateName);
41
+ }
42
+ const unclosed = open.at(-1);
43
+ if (unclosed !== undefined) {
44
+ throw blockError(templateName, unclosed.line, `block "${unclosed.name}" is not closed`);
45
+ }
46
+ return collapseEmptyLines(kept).join("\n");
47
+ }
48
+ function isActive(name, active) {
49
+ if (name === HAS_GUIDE)
50
+ return active.guideFile === "developers" || active.guideFile === "readme";
51
+ return name === active.platform || name === active.guideFile;
52
+ }
53
+ function openBlock(name, line, open, templateName) {
54
+ const outer = open.at(-1);
55
+ if (isPlatform(name)) {
56
+ if (outer !== undefined) {
57
+ throw blockError(templateName, line, `platform block "${name}" inside "${outer.name}"`);
41
58
  }
42
- else {
43
- if (open?.platform !== name) {
44
- throw blockError(templateName, lineNumber, `closing marker "${name}" without its block`);
45
- }
46
- open = undefined;
59
+ return { name, line };
60
+ }
61
+ if (isCondition(name)) {
62
+ if (outer?.name !== "codingAgent") {
63
+ throw blockError(templateName, line, `condition block "${name}" outside a codingAgent block`);
47
64
  }
65
+ return { name, line };
48
66
  }
49
- if (open !== undefined) {
50
- throw blockError(templateName, open.line, `block "${open.platform}" is not closed`);
67
+ throw blockError(templateName, line, `unknown block "${name}"`);
68
+ }
69
+ function closeBlock(name, line, open, templateName) {
70
+ if (!isPlatform(name) && !isCondition(name)) {
71
+ throw blockError(templateName, line, `unknown block "${name}"`);
51
72
  }
52
- return collapseEmptyLines(kept).join("\n");
73
+ if (open.at(-1)?.name !== name) {
74
+ throw blockError(templateName, line, `closing marker "${name}" without its block`);
75
+ }
76
+ open.pop();
53
77
  }
54
78
  function isPlatform(name) {
55
79
  return PLATFORMS.includes(name);
56
80
  }
81
+ function isCondition(name) {
82
+ return name === HAS_GUIDE || GUIDE_FILE_CONDITIONS.includes(name);
83
+ }
57
84
  function blockError(templateName, line, detail) {
58
85
  return new Error(`Error: template ${templateName}, line ${line}: ${detail}.`);
59
86
  }
@@ -3,7 +3,7 @@ import { renderGuideTemplate } from "../guide/render-template.js";
3
3
  import { escapeAdditionalJsonCharacters, formatRange } from "./format.js";
4
4
  // The projects guide serves the OpenClaw playbook only.
5
5
  export function renderProjectsGuide(forms, inventory) {
6
- const guide = renderGuideTemplate("project.md", "openclaw", forms);
6
+ const guide = renderGuideTemplate("project.md", { platform: "openclaw" }, forms);
7
7
  if (inventory === undefined)
8
8
  return guide;
9
9
  const sections = inventory.directories.map((directory) => renderDirectory(inventory, directory));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aligndev",
3
- "version": "0.20.1",
3
+ "version": "0.21.0",
4
4
  "license": "CC0-1.0",
5
5
  "author": "Thomas MUR",
6
6
  "description": "The AlignFirst Dev Kit CLI: the assistant's playbook, coding-agent delegation, and project inventory.",
@@ -236,15 +236,17 @@ Prefer `--message-file` for long or multi-line messages. A quoted heredoc delimi
236
236
 
237
237
  ## Answering the agent's questions
238
238
 
239
- During spec and AAD sessions the agent asks questions before proceeding. Resume **without a protocol** to answer. Compose the answers in English, all questions in one message, numbered to match:
239
+ During spec and AAD sessions the agent asks numbered questions, `Q1`, `Q2`…, each with a ➡️ recommendation. Resume **without a protocol** to answer. Compose the answers in English, all in one message, numbered to match:
240
240
 
241
241
  ```bash
242
242
  {{ALIGNDEV}} code resume <sessionId> --message \
243
- "1 - Explore the codebase and give me your opinion.
244
- 2 - Is that a good design? We need the cleanest code possible.
245
- 3 - Yes, it should be optional."
243
+ "Q1 - Explore the codebase and give me your opinion.
244
+ Q2 - Is that a good design? We need the cleanest code possible.
245
+ Q3 - Yes, it should be optional."
246
246
  ```
247
247
 
248
+ A question your reply skips stays open. Accept a whole round only once your user has settled every decision that is theirs: "All recommendations accepted, except Q3: <what to do instead>."
249
+
248
250
  **Technical questions** — architecture, patterns, existing behavior, anything answerable by reading the code. Never escalate these to the user. Push the agent to investigate: *"Explore the codebase to find out, and give me your opinion."*, *"Do not rush. Take the time to fully understand the situation first."*, *"What would be the elegant, proper, simple yet robust solution?"*, *"Check if a similar pattern is already implemented elsewhere in the codebase."*
249
251
 
250
252
  **Functional or UX questions** — product behavior, user-facing decisions, business rules. These need human judgement: escalate to your user, then relay the answer.
@@ -62,7 +62,7 @@ A value the user did not supply and the lookup did not resolve stays missing. St
62
62
  - `threadName`: the name above
63
63
  - `channel`: `<channel>`
64
64
 
65
- The tool returns the thread's `chat_id` — that is the THREAD_ID. Post the Step 3 starter into the thread: call `message` with `action: "thread-reply"`, `threadId` set to the bare THREAD_ID, `message` set to the starter, and `channel` set to the current surface. Pass no `target`.
65
+ Pass no `message`: content on `thread-create` would post ahead of the starter. The tool returns the thread's `chat_id` — that is the THREAD_ID. Post the Step 3 starter into the thread: call `message` with `action: "thread-reply"`, `threadId` set to the bare THREAD_ID, `message` set to the starter, and `channel` set to the current surface. Pass no `target`.
66
66
 
67
67
  **Slack** — Slack threads have no name. Call `message` with `action: "send"`, `target` set to the raw current `chat_id`, `threadId` set to the triggering message timestamp, `message` set to the Step 3 starter, and `channel` set to the current surface. The bare root timestamp is the THREAD_ID. Slack has no `thread-create`, `thread-reply`, or rename action.
68
68
 
@@ -12,16 +12,22 @@ The user consults you, and you consult the agent. It reads the repository; you w
12
12
  Run `{{ALIGNDEV}} project status <PROJECT_PATH>` and retain its `DEVELOPERS.md` path as DEVELOPERS_PATH. Read DEVELOPERS_PATH and run `{{ALIGNFIRST}} context` from PROJECT_PATH.
13
13
  {{/openclaw}}
14
14
  {{#codingAgent}}
15
+ {{#hasGuide}}
15
16
  Read DEVELOPERS_PATH, retained by Step 1 of `{{ALIGNDEV}} guide working-session`, and run `{{ALIGNFIRST}} context` from PROJECT_PATH.
17
+ {{/hasGuide}}
18
+ {{#noGuide}}
19
+ Run `{{ALIGNFIRST}} context` from PROJECT_PATH.
20
+ {{/noGuide}}
16
21
  {{/codingAgent}}
17
22
 
18
23
  {{#openclaw}}
19
24
  Use the main worktree on the configured default branch. When the question explicitly concerns a branch or a PR, or follows ongoing branch work in this thread, use that branch's existing registered workspace instead: resolve it through the project's workspace guide, and report the limitation rather than inspecting a different branch when no workspace exists. In main-worktree mode (`{{ALIGNDEV}} guide project-workspace-setup`), that workspace is the main worktree while it holds the branch.
20
25
  {{/openclaw}}
21
26
  {{#codingAgent}}
22
- Use the main worktree on the configured default branch. When the question explicitly concerns a branch or a PR, or follows ongoing branch work in this conversation, use that branch's existing registered workspace instead: resolve it through the project's workspace guide, and report the limitation rather than inspecting a different branch when no workspace exists. In main-worktree mode (`{{ALIGNDEV}} guide project-workspace-setup`), that workspace is the main worktree while it holds the branch.
27
+ Use the session's worktree and its branch as they are. When the question explicitly concerns another branch or a PR, use that branch's existing registered workspace instead: resolve it through the project's workspace guide, and report the limitation rather than inspecting a different branch when no workspace exists.
23
28
  {{/codingAgent}}
24
29
 
30
+ {{#openclaw}}
25
31
  ## Step 2 — Refresh the default branch
26
32
 
27
33
  Skip this step when Step 1 selected an existing branch workspace; inspect its current state as it is, without the workspace setup or branch-sync procedure.
@@ -31,6 +37,14 @@ Before delegating against the default branch, verify that the main worktree is c
31
37
  Stop and report the obstacle when the branch is wrong, the worktree is dirty, the upstream is missing, or the refresh fails. Preserve local work: a question is never a reason to switch branches, stash, commit, reset, or resolve a merge.
32
38
 
33
39
  Retain `git rev-parse --short HEAD` after the refresh. Other sessions fast-forward the same worktree, so this records which revision the answer came from. Report it when something in the answer looks inconsistent, and in the Step 5 record.
40
+ {{/openclaw}}
41
+ {{#codingAgent}}
42
+ ## Step 2 — Record the revision
43
+
44
+ Skip the refresh of the default branch: the tree stays as the user left it. A question is never a reason to switch branches, stash, commit, reset, or resolve a merge.
45
+
46
+ Retain `git rev-parse --short HEAD`, the revision the answer comes from. Report it when something in the answer looks inconsistent, and in the Step 5 record.
47
+ {{/codingAgent}}
34
48
 
35
49
  ## Step 3 — Delegate
36
50
 
@@ -41,7 +55,12 @@ Apply the takeover-turn checkpoint in the playbook (`{{ALIGNDEV}} guide`), then
41
55
  Run `{{ALIGNDEV}} code new --message` from the selected worktree, without `--protocol`, `--ticket`, or `--no-ticket`.
42
56
  {{/codingAgent}}
43
57
 
58
+ {{#openclaw}}
44
59
  The message carries the complete question, however detailed, the selected branch, and an explicit constraint to investigate and answer without implementing changes. Include the environment refresh described in the working session when the main branch advanced. Use the delegation guide's background launch and completion procedure.
60
+ {{/openclaw}}
61
+ {{#codingAgent}}
62
+ The message carries the complete question, however detailed, the selected branch, and an explicit constraint to investigate and answer without implementing changes. Use the delegation guide's background launch and completion procedure.
63
+ {{/codingAgent}}
45
64
 
46
65
  Retain the printed session id. Later turns of the same topic resume that session, so the discussion accumulates in one place.
47
66
 
@@ -54,7 +73,12 @@ Answer in the thread, in your own words, grounded in what the agent found.
54
73
  Answer in the conversation, in your own words, grounded in what the agent found.
55
74
  {{/codingAgent}}
56
75
 
76
+ {{#openclaw}}
57
77
  A request for changes ends the consultation: return to the ticket and linked-workspace flow before anything is implemented.
78
+ {{/openclaw}}
79
+ {{#codingAgent}}
80
+ A request for changes ends the consultation: return to the ticket and workspace flow before anything is implemented.
81
+ {{/codingAgent}}
58
82
 
59
83
  ## Step 5 — Record a discussion
60
84
 
@@ -63,14 +63,23 @@ You work on one project: the repository where this session started. Keep these v
63
63
  - **PROJECT** — the main-worktree directory name shown to the user.
64
64
  - **PROJECT_PATH** — the absolute main-worktree path.
65
65
 
66
- Step 1 of `{{ALIGNDEV}} guide working-session` resolves both, and DEVELOPERS_PATH. PROJECT_PATH anchors project-file reads, main-worktree Git commands, and workspace tooling. After workspace setup, use the returned linked-worktree path for branch work and `{{ALIGNDEV}} code`.
66
+ Step 1 of `{{ALIGNDEV}} guide working-session` resolves both, and the workplace: the session's worktree and its branch, by default.
67
+ {{#hasGuide}}
68
+ It also retains DEVELOPERS_PATH, the project's guide for you.
69
+ {{/hasGuide}}
70
+ PROJECT_PATH anchors project-file reads, main-worktree Git commands, and workspace tooling. Branch work and `{{ALIGNDEV}} code` happen in the workplace, which the setup procedure may move to a workspace.
67
71
 
68
72
  Creating, onboarding, or removing a project is not handled in this mode. When the user asks for it, say so.
69
73
  {{/codingAgent}}
70
74
 
71
75
  ## Tickets and AlignFirst protocols
72
76
 
77
+ {{#openclaw}}
73
78
  Code reviews and explicitly requested AlignFirst protocols follow their protocol workflow, including its ticket and workspace requirements. Other read-only questions, advice and brainstormings need no ticket or AlignFirst protocol to start. They use the refreshed main worktree unless they explicitly concern another branch; follow the working session's consultation runbook, which also records a discussion worth keeping.
79
+ {{/openclaw}}
80
+ {{#codingAgent}}
81
+ Code reviews and explicitly requested AlignFirst protocols follow their protocol workflow, including its ticket and workspace requirements. Other read-only questions, advice and brainstormings need no ticket or AlignFirst protocol to start. They use the session's worktree as it is; follow the working session's consultation runbook, which also records a discussion worth keeping.
82
+ {{/codingAgent}}
74
83
 
75
84
  A development task that changes one project needs a TICKET_ID. A project's or deployment's instructions define whether you can create or update tickets. When they provide no ticket-system access, skip those external operations and ask the user for an ID. When the user explicitly says there is no ticket, the working session reserves a side ticket `side-N` before workspace setup. Operational maintenance on existing branches and workspaces does not create a new ticket context.
76
85
 
@@ -117,7 +126,7 @@ Coding runs are long. Run `{{ALIGNDEV}} code` through `exec` in the background,
117
126
  For a `target` parameter, keep the whole `chat_id`, prefix included (e.g. `"channel:#####"`). Never reconstruct, paraphrase, or guess a `chat_id`. A `threadId` parameter is different: pass only the bare thread ID from the conversation metadata or tool result, never a `thread:<channel>/<id>` target.
118
127
  {{/openclaw}}
119
128
  {{#codingAgent}}
120
- To delegate, run `{{ALIGNDEV}} code` from PROJECT_PATH or the linked worktree created from it. Before your first `{{ALIGNDEV}} code` run of a session, run `{{ALIGNDEV}} guide code` and follow it — it is the delegation manual, and it stays the last guide you read. Delegation always goes through `{{ALIGNDEV}} code` — never your own subagents or tasks, and never an AlignFirst protocol skill run by yourself.
129
+ To delegate, run `{{ALIGNDEV}} code` from the workplace, or from PROJECT_PATH for operational work. Before your first `{{ALIGNDEV}} code` run of a session, run `{{ALIGNDEV}} guide code` and follow it — it is the delegation manual, and it stays the last guide you read. Delegation always goes through `{{ALIGNDEV}} code` — never your own subagents or tasks, and never an AlignFirst protocol skill run by yourself.
121
130
 
122
131
  Coding runs are long. Run `{{ALIGNDEV}} code` in the background, as the delegation guide describes.
123
132
  {{/codingAgent}}
@@ -4,10 +4,15 @@
4
4
  The setup phase of a working session: get the workspace ready before handling the user's request. You're in a thread session, so your plain-text replies are your delivery — but only the message that **ends your turn** is guaranteed to post; mid-turn lines may never leave the transcript. The message you end the setup turn with must carry everything the user needs: the `[WORKSPACE]` banner (Step 4) and what you did or launched. Never call `message` `send`/`thread-reply` targeting your own thread: it posts everything twice.
5
5
  {{/openclaw}}
6
6
  {{#codingAgent}}
7
- The setup phase of a working session: get the workspace ready before handling the user's request. The message you end the setup turn with carries the `[WORKSPACE]` banner (Step 4) and what you did or launched.
7
+ The setup phase of a working session: decide the workplace and get it ready before handling the user's request. The message you end the setup turn with carries the `[WORKSPACE]` banner (Step 4) and what you did or launched, or the question Step 2 or Step 5 asks the user.
8
8
  {{/codingAgent}}
9
9
 
10
+ {{#openclaw}}
10
11
  ## Prerequisites — run both now, before Step 1
12
+ {{/openclaw}}
13
+ {{#codingAgent}}
14
+ ## Prerequisites — before Step 1
15
+ {{/codingAgent}}
11
16
 
12
17
  {{#openclaw}}
13
18
  - `{{ALIGNDEV}} guide code` (`exec`) — the delegation manual. Required every time you run this procedure, status requests included; do not skip it because no coding seems planned.
@@ -19,7 +24,9 @@ The setup phase of a working session: get the workspace ready before handling th
19
24
  - run `{{ALIGNDEV}} project status <PROJECT_PATH>` and retain its `DEVELOPERS.md` path as DEVELOPERS_PATH, then read that file when it exists — how to create a worktree or a branch.
20
25
  {{/openclaw}}
21
26
  {{#codingAgent}}
22
- - read DEVELOPERS_PATH, retained by Step 1 of `{{ALIGNDEV}} guide working-session`, when it exists — how to create a worktree or a branch.
27
+ {{#hasGuide}}
28
+ - Read DEVELOPERS_PATH, retained by Step 1 of `{{ALIGNDEV}} guide working-session` — whether the project has workspace tooling, and how to create a worktree or a branch.
29
+ {{/hasGuide}}
23
30
  {{/codingAgent}}
24
31
 
25
32
  ## Step 1 — Requirements
@@ -32,17 +39,40 @@ You need:
32
39
  {{/openclaw}}
33
40
  {{#codingAgent}}
34
41
  - **PROJECT_PATH** — The canonical absolute main-worktree path resolved by Step 1 of `{{ALIGNDEV}} guide working-session`.
42
+ - **The workplace and the default branch** — The session's worktree, its branch, and the project's default branch, retained by the same step.
35
43
  {{/codingAgent}}
36
44
  - **TICKET_ID** — The external ticket ID or the side ticket `side-N` reserved by the working session.
37
45
 
38
46
  If PROJECT, PROJECT_PATH, or TICKET_ID is missing, do not proceed. Do not guess or reconstruct these values. Ask the user.
39
47
 
48
+ {{#openclaw}}
40
49
  ## Step 2 — Post the setup signal
41
50
 
42
- {{#openclaw}}
43
51
  Setting up a workspace takes a while, so tell the user it started before you start it. One short line, in their language, and nothing else — the thread's starter already states the known project, ticket and task, so restating them here just repeats a message they can see.
44
52
  {{/openclaw}}
45
53
  {{#codingAgent}}
54
+ ## Step 2 — Decide the workplace
55
+
56
+ {{#hasGuide}}
57
+ The project has **workspace tooling** when DEVELOPERS_PATH describes workspaces.
58
+ {{/hasGuide}}
59
+ {{#noGuide}}
60
+ The project has no **workspace tooling**.
61
+ {{/noGuide}}
62
+
63
+ The workplace is the first case that matches:
64
+
65
+ 1. **The user's request or instructions name the place** — a directory, a branch, a workspace: work there.
66
+ 2. **The session's branch carries TICKET_ID** — work in place. Skip Steps 3 and 4: post the `[WORKSPACE]` banner (format in Step 4) with the session's worktree and branch and `Status: ready`, then go to Step 5.
67
+ 3. **The session's branch is long-lived** — the default branch, or a name such as `main`, `master`, `develop`, `release` or `production`: open or create the ticket's workspace in Step 4, without asking.
68
+ 4. **Any other branch**, one carrying another ticket's ID included — end the turn on one message asking where to work. On the answer, "here" means the session's worktree as it is, handled as in case 2; a branch or a directory the user names falls under case 1.
69
+
70
+ Without workspace tooling, case 3 also ends the turn on that question, and "here" means the ticket's branch in the session's worktree: `git switch <branch>` when it exists, else a fast-forward of the base branch, then `git switch -c {TICKET_ID}/{1-3-words}`. The banner then follows case 2.
71
+
72
+ ## Step 3 — Post the setup signal
73
+
74
+ Post the signal only when Step 2 opens or creates a workspace.
75
+
46
76
  Setting up a workspace takes a while, so tell the user it started before you start it. One short line, in their language, and nothing else — the user already knows the project, ticket and task, so restating them here just repeats what they have seen.
47
77
  {{/codingAgent}}
48
78
 
@@ -68,27 +98,34 @@ Discord renames a thread through a post, so make the setup signal carry it: send
68
98
 
69
99
  That single call is the whole exception. The post right after it, and every one that follows, is plain text again; with nothing to rename, the tool never targets your own thread.
70
100
  {{/openclaw}}
71
- {{#codingAgent}}
72
- ## Step 3 — Not applicable
73
-
74
- Continue with Step 4.
75
- {{/codingAgent}}
76
101
 
102
+ {{#openclaw}}
77
103
  ## Step 4 — Set up the project workspace (worktree, branch, dev server)
104
+ {{/openclaw}}
105
+ {{#codingAgent}}
106
+ ## Step 4 — Set up the workspace (worktree, branch, dev server)
107
+ {{/codingAgent}}
78
108
 
79
109
  {{#openclaw}}
80
110
  A project runs in **main-worktree mode** when DEVELOPERS_PATH is missing or has no workspaces section. Its main worktree at PROJECT_PATH is its only workspace, used by one working thread at a time. "Main-worktree mode" below adapts this step, and wherever the playbook names the linked workspace, you use PROJECT_PATH.
81
111
  {{/openclaw}}
82
- {{#codingAgent}}
83
- A project runs in **main-worktree mode** when DEVELOPERS_PATH is missing or has no workspaces section. Its main worktree at PROJECT_PATH is its only workspace, used by one working session at a time. "Main-worktree mode" below adapts this step, and wherever the playbook names the linked workspace, you use PROJECT_PATH.
84
- {{/codingAgent}}
85
112
 
113
+ {{#openclaw}}
86
114
  Otherwise, the workspace tooling owns worktrees. Run its main-worktree commands from PROJECT_PATH. Create, reuse, and tear worktrees down through its commands only — never `git worktree add`/`remove`/`prune`, never `rm -rf` on a worktree directory, never a branch checked out by hand outside a workspace. A worktree the tooling doesn't know about is invisible to every other session.
115
+ {{/openclaw}}
116
+ {{#codingAgent}}
117
+ The workspace tooling owns worktrees. Run its main-worktree commands from PROJECT_PATH. Create, reuse, and tear worktrees down through its commands only — never `git worktree add`/`remove`/`prune`, never `rm -rf` on a worktree directory, never a branch checked out by hand outside a workspace. A worktree the tooling doesn't know about is invisible to every other session.
118
+ {{/codingAgent}}
87
119
 
88
120
  First, fetch remote refs from PROJECT_PATH with `git fetch --prune`. Then check what already exists for the {TICKET_ID} — two checks, both required:
89
121
 
90
122
  - **Branch**: from PROJECT_PATH, list the branches, local and remote (`git branch -a`), and look for one matching the {TICKET_ID}. No match means no branch yet — an answer, not a failure.
123
+ {{#openclaw}}
91
124
  - **Registered workspaces**: `DEVELOPERS.md` names the project's guide command (`workspace --guide`, with the project's own runner). It gives the commands to **list registered workspaces** and to **set up a workspace** — on an existing branch, or on a new one. Use them.
125
+ {{/openclaw}}
126
+ {{#codingAgent}}
127
+ - **Registered workspaces**: the workspace tooling's guide command (`workspace --guide`, with the project's own runner) gives the commands to **list registered workspaces** and to **set up a workspace** — on an existing branch, or on a new one. Use them.
128
+ {{/codingAgent}}
92
129
 
93
130
  Never assume the branch is new; `git worktree list` alone does not answer the branch question.
94
131
 
@@ -102,7 +139,7 @@ Whenever a branch exists, you work from its workspace — a status request inclu
102
139
  The moment you have the linked workspace path — attached (sub-path 1) or freshly set up (2, 3) — post the `[WORKSPACE]` banner, before any `git` inspection or prose, and **include it again in the message you end the turn with**: the early post may not deliver on every surface, the final message always does (on Discord the Step 3 rename post also delivers). `workspace setup` blocks until the bootstrap reaches `ready` or `failed`; run it in the foreground (no `background` option) and report the state it returns. Run subsequent Git commands and `{{ALIGNDEV}} code` from that linked workspace, never PROJECT_PATH, except in main-worktree mode.
103
140
  {{/openclaw}}
104
141
  {{#codingAgent}}
105
- The moment you have the linked workspace path — attached (sub-path 1) or freshly set up (2, 3) — post the `[WORKSPACE]` banner, before any `git` inspection or prose. `workspace setup` blocks until the bootstrap reaches `ready` or `failed`; run it in the foreground and report the state it returns. Run subsequent Git commands and `{{ALIGNDEV}} code` from that linked workspace, never PROJECT_PATH, except in main-worktree mode.
142
+ The moment you have the workplace — in place, attached (sub-path 1) or freshly set up (2, 3) — post the `[WORKSPACE]` banner, before any `git` inspection or prose. `workspace setup` blocks until the bootstrap reaches `ready` or `failed`; run it in the foreground and report the state it returns. Run subsequent Git commands and `{{ALIGNDEV}} code` from the workplace.
106
143
  {{/codingAgent}}
107
144
 
108
145
  {{#openclaw}}
@@ -122,15 +159,15 @@ Status: {running | ready | failed}
122
159
 
123
160
  The lines below the tag report the workspace: after `Status:`, add what the setup output gives that the user can act on.
124
161
 
162
+ {{#openclaw}}
125
163
  ### Main-worktree mode
164
+ {{/openclaw}}
126
165
 
127
166
  {{#openclaw}}
128
167
  The branch check applies; the registered-workspace check does not. Before any checkout, claim the main worktree. It is free when it is on the default branch with a clean `git status`, or already on this thread's {TICKET_ID} branch. Otherwise, end the turn telling the user the project is busy: name the checked-out branch and the uncommitted changes, and change nothing.
129
168
  {{/openclaw}}
130
- {{#codingAgent}}
131
- The branch check applies; the registered-workspace check does not. Before any checkout, claim the main worktree. It is free when it is on the default branch with a clean `git status`, or already on this session's {TICKET_ID} branch. Otherwise, end the turn telling the user the project is busy: name the checked-out branch and the uncommitted changes, and change nothing.
132
- {{/codingAgent}}
133
169
 
170
+ {{#openclaw}}
134
171
  On a free main worktree, the sub-paths above run in PROJECT_PATH with plain `git switch`:
135
172
 
136
173
  1. **Already on the branch** → use it.
@@ -138,8 +175,18 @@ On a free main worktree, the sub-paths above run in PROJECT_PATH with plain `git
138
175
  3. **No branch** → a status request ends as above. Otherwise, fast-forward the base branch as above, then `git switch -c {TICKET_ID}/{1-3-words}`.
139
176
 
140
177
  The `[WORKSPACE]` banner names the main worktree: `Worktree:` is the directory name of PROJECT_PATH, and `Status:` is `ready`.
178
+ {{/openclaw}}
141
179
 
180
+ {{#openclaw}}
142
181
  ## Step 5 — Sync an existing branch on takeover (sub-paths 1 & 2)
182
+ {{/openclaw}}
183
+ {{#codingAgent}}
184
+ ## Step 5 — Sync an existing branch
185
+ {{/codingAgent}}
186
+
187
+ {{#codingAgent}}
188
+ In place on an existing branch, fetch first. A fast-forward of the branch onto its remote counterpart or onto the base branch, on a clean tree, is the only sync done without asking: do it, then report it in one line. Anything else — uncommitted changes, a remote branch that does not fast-forward, a base-branch catch-up that needs a merge commit — ends the turn on one message stating what will happen ("I'll commit your changes as WIP and merge `main`, OK?"). The list below runs on the user's yes. In a workspace you opened or created, the list runs directly.
189
+ {{/codingAgent}}
143
190
 
144
191
  Skip on sub-path 3 (no branch — nothing to sync). Otherwise, once the workspace is set up, bring the branch up to date *before* inspecting, working, or reporting a status — a teammate may have pushed since you last synced, and a report off a stale branch is wrong. In order:
145
192
 
@@ -10,7 +10,7 @@ Your plain text is your reply, on Discord and Slack alike, and only the message
10
10
  Keep progress and completion reports in this thread. A request to notify the user means reply here; use a DM or another surface only when the user explicitly names that destination.
11
11
  {{/openclaw}}
12
12
  {{#codingAgent}}
13
- You're handling work in this conversation, on one project: the repository where this session started. Workspace, consultation, and coding happen here.
13
+ You're handling work in this conversation, on one project: the repository where this session started. Workspace, consultation, and coding happen here. The session's worktree and its branch are your workplace by default.
14
14
 
15
15
  Keep progress and completion reports in this conversation. A request to notify the user means a reply here.
16
16
  {{/codingAgent}}
@@ -52,9 +52,16 @@ A takeover turn starts with the plugin's `Take over this thread.` message from `
52
52
  Outside a git repository, tell the user to start the session inside the project's repository, and stop. Otherwise, resolve the project before any other step:
53
53
 
54
54
  - PROJECT_PATH is the main worktree of the session's working directory: the parent of `git rev-parse --path-format=absolute --git-common-dir`. PROJECT is its directory name.
55
- - Run `{{ALIGNFIRST}} config --json` from PROJECT_PATH and retain `locations["DEVELOPERS.md"].path` as DEVELOPERS_PATH. The report also names the project's companion directory, where its AlignFirst files may live.
55
+ - The workplace is the session's worktree (`git rev-parse --show-toplevel`) and its branch (`git branch --show-current`).
56
+ - Run `{{ALIGNFIRST}} config --json` from PROJECT_PATH. The default branch is `config.git.defaultBranch` in the report, else `git symbolic-ref --short refs/remotes/origin/HEAD` without its `origin/` prefix. The report also names the project's companion directory, where its AlignFirst files may live.
57
+ {{#developers}}
58
+ - Retain `locations["DEVELOPERS.md"].path` from the report as DEVELOPERS_PATH.
59
+ {{/developers}}
60
+ {{#readme}}
61
+ - Retain `README.md` at the root of PROJECT_PATH as DEVELOPERS_PATH: the project has no `DEVELOPERS.md`, and its README is your guide.
62
+ {{/readme}}
56
63
 
57
- These values hold for the whole session.
64
+ These values hold for the whole session. Only `{{ALIGNDEV}} guide project-workspace-setup` moves the workplace.
58
65
  {{/codingAgent}}
59
66
 
60
67
  {{#openclaw}}
@@ -91,7 +98,7 @@ Everything else is unchanged: the same runbooks, the same ticket rules, the same
91
98
  {{#codingAgent}}
92
99
  ### Step 2 — Recover the request
93
100
 
94
- The request comes from this conversation; later messages supply missing values or correct it. TICKET_ID comes from the user, a resource URL, or the current branch name when it carries one. Branch, linked-worktree path, and dev-server URL live in the conversation under `[WORKSPACE]`.
101
+ The request comes from this conversation; later messages supply missing values or correct it. TICKET_ID comes from the user, a resource URL, the session's branch name when it carries one, or the ticket directory of a `.plans/` path the user names, such as a plan to execute. Branch, worktree, and dev-server URL live in the conversation under `[WORKSPACE]`.
95
102
  {{/codingAgent}}
96
103
 
97
104
  ### Step 3 — Resolve deferred context
@@ -152,7 +159,15 @@ Skip this step for read-only questions and operational work.
152
159
 
153
160
  For new single-project work where the user explicitly says there is no ticket or asks for a side ticket:
154
161
 
162
+ {{#openclaw}}
155
163
  1. Read DEVELOPERS_PATH and run `{{ALIGNFIRST}} context` from PROJECT_PATH.
164
+ {{/openclaw}}
165
+ {{#codingAgent}}
166
+ 1. Run `{{ALIGNFIRST}} context` from PROJECT_PATH.
167
+ {{#hasGuide}}
168
+ Read DEVELOPERS_PATH.
169
+ {{/hasGuide}}
170
+ {{/codingAgent}}
156
171
  2. Run `{{ALIGNFIRST}} sync`, so identifier selection sees the current shared task set.
157
172
  {{#openclaw}}
158
173
  3. Run `{{ALIGNFIRST}} ticket --side` from PROJECT_PATH (`exec`). It creates the ticket directory and prints it as TICKET_DIR; TICKET_ID is the `side-N` it reports.
@@ -172,7 +187,7 @@ For new single-project work where the user explicitly says there is no ticket or
172
187
  The bot owns this reservation and the request capture; the agent receives TICKET_ID. Do not use `{{ALIGNDEV}} code new --no-ticket`: TICKET_ID must exist before delegation, for the request file and the workspace. Continue to workspace setup with the side ticket as TICKET_ID, then run the coding protocol from the returned linked worktree.
173
188
  {{/openclaw}}
174
189
  {{#codingAgent}}
175
- You own this reservation and the request capture; the agent receives TICKET_ID. Do not use `{{ALIGNDEV}} code new --no-ticket`: TICKET_ID must exist before delegation, for the request file and the workspace. Continue to workspace setup with the side ticket as TICKET_ID, then run the coding protocol from the returned linked worktree.
190
+ You own this reservation and the request capture; the agent receives TICKET_ID. Do not use `{{ALIGNDEV}} code new --no-ticket`: TICKET_ID must exist before delegation, for the request file and the workspace. Continue with `{{ALIGNDEV}} guide project-workspace-setup`, which decides the workplace with the side ticket as TICKET_ID, then run the coding protocol from that workplace.
176
191
  {{/codingAgent}}
177
192
 
178
193
  {{#openclaw}}
@@ -190,7 +205,7 @@ The question on every turn is not a mode but a fact: does this request need a pr
190
205
  - **The request is a single-project change, protocol request, or ticket status request** — require PROJECT, PROJECT_PATH, and TICKET_ID. A starter with a request block is filed first ("Detailed requests" below). Then run `{{ALIGNDEV}} guide project-workspace-setup`, read it fully, and complete it before any other action, `git log` and codebase inspection included. Your first post is its setup signal (Step 2); the procedure attaches or sets up the workspace, whatever exists, and posts the `[WORKSPACE]` banner.
191
206
  {{/openclaw}}
192
207
  {{#codingAgent}}
193
- - **The request is a single-project change, protocol request, or ticket status request** — require PROJECT, PROJECT_PATH, and TICKET_ID. A detailed request is filed first ("Detailed requests" below). Then run `{{ALIGNDEV}} guide project-workspace-setup`, read it fully, and complete it before any other action, `git log` and codebase inspection included. Your first post is its setup signal (Step 2); the procedure attaches or sets up the workspace, whatever exists, and posts the `[WORKSPACE]` banner.
208
+ - **The request is a single-project change, protocol request, or ticket status request** — require PROJECT, PROJECT_PATH, and TICKET_ID. A detailed request is filed first ("Detailed requests" below). Then run `{{ALIGNDEV}} guide project-workspace-setup`, read it fully, and complete it before any other action, `git log` and codebase inspection included. The procedure decides the workplace (in place, a workspace, or a question to the user) and posts the `[WORKSPACE]` banner once it is known.
194
209
  {{/codingAgent}}
195
210
  - **A required value is missing** — go to Step 7. Resolve or ask for it there. The moment the required values are known, follow the matching path above.
196
211
 
@@ -198,7 +213,7 @@ The question on every turn is not a mode but a fact: does this request need a pr
198
213
  Changes to an existing project happen inside a linked workspace. Read-only questions use the main worktree by default. The lifecycle procedure also uses it for new-project bootstrap through its initial commit and repository onboarding on a setup branch.
199
214
  {{/openclaw}}
200
215
  {{#codingAgent}}
201
- Changes to an existing project happen inside a linked workspace. Read-only questions use the main worktree by default.
216
+ Changes happen in the workplace the setup procedure decides. Read-only questions use the session's worktree as it is.
202
217
  {{/codingAgent}}
203
218
 
204
219
  ### Step 7 — Handle the actual request
@@ -254,7 +269,12 @@ When one project owns a detailed change request, preserve it before delegation:
254
269
  5. When ticket editing is available, add the request-file path relative to the project to the ticket description.
255
270
  6. Continue through project workspace setup and `{{ALIGNDEV}} code` as usual.
256
271
 
272
+ {{#openclaw}}
257
273
  When Step 5 reserved a side ticket `side-N`, the request is already captured. Continue through project workspace setup and delegate from the linked worktree.
274
+ {{/openclaw}}
275
+ {{#codingAgent}}
276
+ When Step 5 reserved a side ticket `side-N`, the request is already captured. Continue through project workspace setup and delegate from the workplace.
277
+ {{/codingAgent}}
258
278
 
259
279
  {{#openclaw}}
260
280
  Skip this capture workflow for a multi-project request with no main project and for operational work such as workspace cleanup or base-branch refresh. Delegate those requests to the agent without an AlignFirst protocol.
@@ -282,7 +302,12 @@ Delegate to the agent: workspace/branch/worktree creation, writing code (`alignf
282
302
 
283
303
  Thinking is delegated too. When you need *ideas*, a *design* direction, an *opinion*, or an approach — for the user or for your own next step — put the question to the agent and build on its answer. Never brainstorm alone: the agent grounds its ideas in the codebase; yours would come from memory. `{{ALIGNDEV}} guide consultation` is the procedure.
284
304
 
305
+ {{#openclaw}}
285
306
  Global tools go in the prompt. Run `{{ALIGNDEV}} code` from the linked workspace for changes and from PROJECT_PATH only when the procedure explicitly works in the main worktree. The agent knows only that directory's project context: it can run the globally installed tools your own context lists, but it doesn't know they exist. When a delegated task can use one, name it in the prompt as **globally installed**. A task you would have kept because it needs such a tool is one more thing to delegate.
307
+ {{/openclaw}}
308
+ {{#codingAgent}}
309
+ Global tools go in the prompt. Run `{{ALIGNDEV}} code` from the workplace, unless a procedure names another directory. The agent knows only that directory's project context: it can run the globally installed tools your own context lists, but it doesn't know they exist. When a delegated task can use one, name it in the prompt as **globally installed**. A task you would have kept because it needs such a tool is one more thing to delegate.
310
+ {{/codingAgent}}
286
311
 
287
312
  Every single-project change delegation carries TICKET_ID in the `{{ALIGNDEV}} code` invocation or message as the delegation guide allows. Read-only questions omit the ticket option; a ticket mentioned by the user stays in the question's context. Operational maintenance may instead identify its existing branches and workspaces directly.
288
313
 
@@ -313,7 +338,17 @@ After writing or editing any file under `.plans/` yourself, run `{{ALIGNFIRST}}
313
338
  A project has up to three entry points:
314
339
 
315
340
  - `README.md` — presentation, getting-started procedure…
341
+ {{#openclaw}}
342
+ - `DEVELOPERS.md` — the agent's user, human or AI: you. Read it at DEVELOPERS_PATH.
343
+ {{/openclaw}}
344
+ {{#codingAgent}}
345
+ {{#developers}}
316
346
  - `DEVELOPERS.md` — the agent's user, human or AI: you. Read it at DEVELOPERS_PATH.
347
+ {{/developers}}
348
+ {{#readme}}
349
+ - `DEVELOPERS.md` — the agent's user, human or AI: you. This project has none, so `README.md` is also your guide, read at DEVELOPERS_PATH.
350
+ {{/readme}}
351
+ {{/codingAgent}}
317
352
  - `AGENTS.md` — the agent. When the project's instructions come from its companion, the companion's `.alignfirst.md` replaces it for the agent, and `{{ALIGNFIRST}} context` prints it.
318
353
 
319
354
  The rest of the documentation (`docs/`, …) addresses everybody.
@@ -327,23 +362,17 @@ A project can have documentation files. List them all from PROJECT_PATH, the ful
327
362
  {{#openclaw}}
328
363
  A project in main-worktree mode (`{{ALIGNDEV}} guide project-workspace-setup`) is the exception to this section: its main worktree leaves the base branch while a working thread holds it, and the edits happen there, on the thread's branch.
329
364
  {{/openclaw}}
330
- {{#codingAgent}}
331
- A project in main-worktree mode (`{{ALIGNDEV}} guide project-workspace-setup`) is the exception to this section: its main worktree leaves the base branch while a working session holds it, and the edits happen there, on the session's branch.
332
- {{/codingAgent}}
333
365
 
334
366
  {{#openclaw}}
335
367
  The main worktree at PROJECT_PATH stays on the base branch, except for the repository-onboarding setup branch defined in `{{ALIGNDEV}} guide project-lifecycle`. It is shared across sessions.
336
368
  {{/openclaw}}
337
369
  {{#codingAgent}}
338
- The main worktree at PROJECT_PATH stays on the base branch. It is shared across sessions.
370
+ The main worktree at PROJECT_PATH belongs to the user. Edits on the base branch happen only when the user chose to work there.
339
371
  {{/codingAgent}}
340
372
 
341
373
  {{#openclaw}}
342
374
  Never edit files while the base branch is checked out, except while bootstrapping a new project before its initial commit as defined in `{{ALIGNDEV}} guide project-lifecycle`.
343
375
  {{/openclaw}}
344
- {{#codingAgent}}
345
- Never edit files while the base branch is checked out.
346
- {{/codingAgent}}
347
376
 
348
377
  Install dependencies in the main worktree from the committed lockfile, without rewriting it: `npm ci` with npm, or the frozen-lockfile install of the project's package manager. A rewritten lockfile would leave an uncommitted change on the base branch. Every prompt to the agent that installs dependencies in the main worktree states this rule.
349
378
 
@@ -351,11 +380,18 @@ Running the dev-server from the main worktree is fine.
351
380
 
352
381
  ### Linked worktrees and other branches
353
382
 
383
+ {{#openclaw}}
354
384
  A project in main-worktree mode has no linked worktree: its branches are created and checked out in the main worktree with plain `git switch`, and the rule against a hand-made checkout does not apply to it. `git worktree add`/`remove`/`prune` stay out of bounds.
355
385
 
356
386
  After a project's initial commit exists, editing the codebase happens on another branch in a linked worktree. If you need one and it doesn't exist yet, follow the `{{ALIGNDEV}} guide project-workspace-setup` instructions to set it up.
357
387
 
358
388
  Worktrees belong to the workspace tooling. Every creation, reuse, and teardown goes through its commands — run the guide `DEVELOPERS.md` points to (`workspace --guide`) to get them. `git worktree add`/`remove`/`prune` and deleting a worktree directory are out of bounds, and so is a hand-made branch checkout outside a workspace. The registry is what makes a worktree visible to the other sessions and to the dev-server tooling.
389
+ {{/openclaw}}
390
+ {{#codingAgent}}
391
+ A project with workspace tooling (Step 2 of `{{ALIGNDEV}} guide project-workspace-setup`) owns its worktrees through it. Every creation, reuse, and teardown goes through the commands its guide (`workspace --guide`) gives. `git worktree add`/`remove`/`prune` and deleting a worktree directory are out of bounds. The registry is what makes a worktree visible to the other sessions and to the dev-server tooling.
392
+
393
+ Without workspace tooling, create a worktree with `git worktree add` only when the user asks for one.
394
+ {{/codingAgent}}
359
395
 
360
396
  ### Updating a branch with the base branch
361
397
 
@@ -390,7 +426,12 @@ Delegate the sequence to the agent.
390
426
 
391
427
  ### Status update
392
428
 
429
+ {{#openclaw}}
393
430
  - Check status from the recorded linked-worktree path. The takeover sync in `{{ALIGNDEV}} guide project-workspace-setup` has already fetched and merged the remote branch, so you are reporting the latest state.
431
+ {{/openclaw}}
432
+ {{#codingAgent}}
433
+ - Check status from the workplace. The sync in `{{ALIGNDEV}} guide project-workspace-setup` has already fetched and merged the remote branch, so you are reporting the latest state.
434
+ {{/codingAgent}}
394
435
  - Report where the work stands, drawing on two complementary sources: repo/workflow metadata you gather directly (`git log`/`status`/branch, `gh` PR state), and the ticket's AlignFirst artifacts via `{{ALIGNDEV}} code new --ticket <id> --catchup` (the agent synthesizes the ticket history). Don't browse the source to describe the code; that's a separate delegation.
395
436
 
396
437
  ### Dev-server while working
@@ -457,7 +498,12 @@ A project whose `.alignfirst.md` or `DEVELOPERS.md` resolves in its companion (`
457
498
 
458
499
  Two triggers, both edited through the agent:
459
500
 
501
+ {{#openclaw}}
460
502
  - You learn something non-obvious about how to work in a project — a command, a quirk, a convention not yet written down. Propose capturing it in DEVELOPERS_PATH, ask for confirmation, then have the agent make the edit.
503
+ {{/openclaw}}
504
+ {{#codingAgent}}
505
+ - You learn something non-obvious about how to work in a project — a command, a quirk, a convention not yet written down. Propose capturing it in the project's `DEVELOPERS.md`, created at the repository root when the project has none, ask for confirmation, then have the agent make the edit.
506
+ {{/codingAgent}}
461
507
  {{#openclaw}}
462
508
  - The user asks to retain a rule for the project. No confirmation needed: the rule goes into both `AGENTS.md` and `DEVELOPERS.md`. When the thread has an active ticket and the rule is simple, add it on the current branch, so the ticket's PR carries it. When the rule is complex or the thread has no ticket, reserve a side ticket (Step 5), set up a workspace on a new branch for the rule, and create a ready pull request.
463
509
  {{/openclaw}}
@@ -533,7 +579,12 @@ After creating the MR/PR (via `{{ALIGNDEV}} code`):
533
579
 
534
580
  Whenever you observe that a PR/MR is merged, delegate the post-merge maintenance to the agent without a protocol:
535
581
 
582
+ {{#openclaw}}
536
583
  1. Remove the source branch's registered project workspace through the project's workspace tooling, when one exists. In main-worktree mode, switch the main worktree back to the merge target instead.
584
+ {{/openclaw}}
585
+ {{#codingAgent}}
586
+ 1. Remove the source branch's registered project workspace through the project's workspace tooling, when one exists. A branch worked on in place stays checked out: the user decides when to leave it.
587
+ {{/codingAgent}}
537
588
  2. Refresh the merge target in the main worktree without switching the main worktree away from its base branch. Fetch and fast-forward it, then reinstall dependencies, rebuild, and run new migrations when the project requires them.
538
589
  3. Report the removed workspace and refreshed branch.
539
590
 
@@ -585,4 +636,9 @@ Creating a project, onboarding a repository to clone, or physically removing a p
585
636
  ### Forbidden
586
637
 
587
638
  - Never force push. Never rebase, reset, or amend a commit that exists on the remote.
639
+ {{#openclaw}}
588
640
  - Never touch a worktree outside the workspace tooling. The main worktree of a project in main-worktree mode is the exception.
641
+ {{/openclaw}}
642
+ {{#codingAgent}}
643
+ - Never touch a worktree outside the workspace tooling when the project has it. Without tooling, create or remove a worktree only when the user asks.
644
+ {{/codingAgent}}