@windyroad/architect 0.20.0-preview.946 → 0.20.1
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/.agents/plugins/marketplace.json +12 -0
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/agents/test/architect-codex-eval-contract.bats +8 -4
- package/bin/install.mjs +56 -7
- package/hooks/architect-mark-reviewed.sh +4 -8
- package/hooks/codex-agent-completion.mjs +61 -0
- package/hooks/hooks.json +5 -1
- package/hooks/test/architect-mark-reviewed-verdict-grep.bats +7 -20
- package/hooks/test/codex-agent-completion.bats +64 -0
- package/package.json +6 -1
- package/scripts/codex-agent.mjs +99 -0
- package/scripts/sync-codex-skills.mjs +85 -0
- package/scripts/test/codex-pack-and-agent.bats +86 -0
- package/skills/capture-adr/SKILL.md +25 -14
- package/skills/create-adr/SKILL.md +43 -32
- package/skills/create-adr/test/create-adr-codex-eval-contract.bats +7 -3
- package/skills/review-decisions/SKILL.md +24 -13
- package/skills/review-design/SKILL.md +14 -3
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "windyroad-architect-local",
|
|
3
|
+
"interface": { "displayName": "Windy Road Architect" },
|
|
4
|
+
"plugins": [
|
|
5
|
+
{
|
|
6
|
+
"name": "wr-architect",
|
|
7
|
+
"source": { "source": "local", "path": "." },
|
|
8
|
+
"policy": { "installation": "AVAILABLE", "authentication": "ON_INSTALL" },
|
|
9
|
+
"category": "Developer Tools"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -17,13 +17,17 @@ setup() {
|
|
|
17
17
|
[ "$status" -eq 0 ]
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
@test "architect Codex agent eval runner uses
|
|
21
|
-
run grep -n
|
|
20
|
+
@test "architect Codex agent eval runner uses packed install and exact custom agent" {
|
|
21
|
+
run grep -n 'npm pack' "$EVAL_DIR/run-codex-agent-eval.sh"
|
|
22
22
|
[ "$status" -eq 0 ]
|
|
23
|
-
run grep -n
|
|
23
|
+
run grep -n 'windyroad-architect --runtime codex --scope user' "$EVAL_DIR/run-codex-agent-eval.sh"
|
|
24
24
|
[ "$status" -eq 0 ]
|
|
25
25
|
run grep -n "codex exec" "$EVAL_DIR/run-codex-agent-eval.sh"
|
|
26
26
|
[ "$status" -eq 0 ]
|
|
27
|
-
run grep -n
|
|
27
|
+
run grep -n 'agents/wr-architect-agent.toml' "$EVAL_DIR/run-codex-agent-eval.sh"
|
|
28
|
+
[ "$status" -eq 0 ]
|
|
29
|
+
run grep -n 'wr-architect:agent' "$EVAL_DIR/run-codex-agent-eval.sh"
|
|
30
|
+
[ "$status" -eq 0 ]
|
|
31
|
+
run grep -n 'git -C "$TMP_REPO" init' "$EVAL_DIR/run-codex-agent-eval.sh"
|
|
28
32
|
[ "$status" -eq 0 ]
|
|
29
33
|
}
|
package/bin/install.mjs
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
6
|
import { fileURLToPath } from "node:url";
|
|
5
7
|
|
|
6
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
9
|
const utils = await import(resolve(__dirname, "../lib/install-utils.mjs"));
|
|
8
|
-
|
|
10
|
+
const agents = await import(resolve(__dirname, "../scripts/codex-agent.mjs"));
|
|
9
11
|
const PLUGIN = "wr-architect";
|
|
10
|
-
const
|
|
12
|
+
const CODEX_MARKETPLACE = "windyroad-architect-local";
|
|
13
|
+
const PACKAGE_ROOT = resolve(__dirname, "..");
|
|
14
|
+
const PACKAGE_VERSION = JSON.parse(readFileSync(join(PACKAGE_ROOT, "package.json"), "utf8")).version;
|
|
15
|
+
|
|
16
|
+
function marketplaceRoot() {
|
|
17
|
+
const home = process.env.CODEX_HOME || join(homedir(), ".codex");
|
|
18
|
+
return join(home, ".tmp", "marketplaces", `wr-architect-${PACKAGE_VERSION}`);
|
|
19
|
+
}
|
|
11
20
|
|
|
12
21
|
const flags = utils.parseStandardArgs(process.argv);
|
|
13
22
|
|
|
23
|
+
if (flags.runtime === "codex" || flags.runtime === "both") {
|
|
24
|
+
const bundled = "/Applications/ChatGPT.app/Contents/Resources/codex";
|
|
25
|
+
const binary = process.env.CODEX_BINARY || (existsSync(bundled) ? bundled : null);
|
|
26
|
+
if (binary?.includes("/")) process.env.PATH = `${dirname(binary)}:${process.env.PATH || ""}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
14
29
|
if (flags.help) {
|
|
15
30
|
console.log(`
|
|
16
31
|
Usage: npx @windyroad/architect [options]
|
|
@@ -32,13 +47,47 @@ if (flags.dryRun) {
|
|
|
32
47
|
utils.setDryRun(true);
|
|
33
48
|
console.log("[dry-run mode — no commands will be executed]\n");
|
|
34
49
|
}
|
|
35
|
-
|
|
36
50
|
utils.checkPrerequisites({ runtime: flags.runtime });
|
|
37
51
|
|
|
52
|
+
function codexInstall() {
|
|
53
|
+
const root = marketplaceRoot();
|
|
54
|
+
if (!flags.dryRun) {
|
|
55
|
+
rmSync(root, { recursive: true, force: true });
|
|
56
|
+
mkdirSync(dirname(root), { recursive: true });
|
|
57
|
+
cpSync(PACKAGE_ROOT, root, { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
if (!utils.run(`codex plugin marketplace add ${JSON.stringify(root)}`, `Codex marketplace: ${CODEX_MARKETPLACE}`)) return false;
|
|
60
|
+
if (!utils.run(`codex plugin add ${PLUGIN}@${CODEX_MARKETPLACE}`, PLUGIN)) return false;
|
|
61
|
+
if (!flags.dryRun) agents.installArchitectAgent(agents.agentDir(flags.scope));
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function codexUninstall() {
|
|
66
|
+
const removed = utils.run(`codex plugin remove ${PLUGIN}@${CODEX_MARKETPLACE}`, `Removing ${PLUGIN}`);
|
|
67
|
+
utils.run(`codex plugin marketplace remove ${CODEX_MARKETPLACE}`, `Removing ${CODEX_MARKETPLACE}`);
|
|
68
|
+
if (!flags.dryRun) {
|
|
69
|
+
for (const target of new Set([agents.agentDir(flags.scope), agents.agentDir("user")])) {
|
|
70
|
+
agents.uninstallArchitectAgent(target);
|
|
71
|
+
}
|
|
72
|
+
rmSync(marketplaceRoot(), { recursive: true, force: true });
|
|
73
|
+
}
|
|
74
|
+
return removed;
|
|
75
|
+
}
|
|
76
|
+
|
|
38
77
|
if (flags.uninstall) {
|
|
39
|
-
utils.uninstallPackage(PLUGIN, { runtime:
|
|
78
|
+
if (flags.runtime === "claude" || flags.runtime === "both") utils.uninstallPackage(PLUGIN, { runtime: "claude" });
|
|
79
|
+
if ((flags.runtime === "codex" || flags.runtime === "both") && !codexUninstall()) process.exit(1);
|
|
40
80
|
} else if (flags.update) {
|
|
41
|
-
utils.updatePackage(PLUGIN, { scope: flags.scope, runtime:
|
|
81
|
+
if (flags.runtime === "claude" || flags.runtime === "both") utils.updatePackage(PLUGIN, { scope: flags.scope, runtime: "claude" });
|
|
82
|
+
if ((flags.runtime === "codex" || flags.runtime === "both") && !codexInstall()) process.exit(1);
|
|
83
|
+
} else if (flags.runtime === "codex") {
|
|
84
|
+
console.log(`\nInstalling @windyroad/architect (${flags.scope} scope)...\n`);
|
|
85
|
+
if (!codexInstall()) process.exit(1);
|
|
86
|
+
console.log("\nDone! Restart Codex to activate.\n");
|
|
87
|
+
} else if (flags.runtime === "both") {
|
|
88
|
+
utils.installPackage(PLUGIN, { scope: flags.scope, runtime: "claude" });
|
|
89
|
+
if (!codexInstall()) process.exit(1);
|
|
90
|
+
console.log("\nDone! Restart Claude Code and Codex to activate.\n");
|
|
42
91
|
} else {
|
|
43
|
-
utils.installPackage(PLUGIN, {
|
|
92
|
+
utils.installPackage(PLUGIN, { scope: flags.scope, runtime: "claude" });
|
|
44
93
|
}
|
|
@@ -49,10 +49,7 @@ case "$SUBAGENT" in
|
|
|
49
49
|
# per 3-filing session).
|
|
50
50
|
MARKER="/tmp/architect-reviewed-${SESSION_ID}"
|
|
51
51
|
case "$VERDICT" in
|
|
52
|
-
PASS
|
|
53
|
-
# PASS or unparseable verdict — allow with marker (the empty case
|
|
54
|
-
# preserves the pre-amendment "could not parse verdict" backward-
|
|
55
|
-
# compat allow-with-marker behaviour to avoid lockout).
|
|
52
|
+
PASS)
|
|
56
53
|
if [ -d "$PROJECT_DIR/docs/decisions" ]; then
|
|
57
54
|
HASH=$(_substance_hash_path "$PROJECT_DIR/docs/decisions")
|
|
58
55
|
else
|
|
@@ -62,13 +59,12 @@ case "$SUBAGENT" in
|
|
|
62
59
|
echo "WARN: architect-mark-reviewed atomic marker-write failed for ${MARKER}" >&2
|
|
63
60
|
fi
|
|
64
61
|
;;
|
|
65
|
-
FAIL)
|
|
66
|
-
#
|
|
62
|
+
FAIL|"")
|
|
63
|
+
# Fail closed: issues and unparseable output do not unlock edits.
|
|
67
64
|
;;
|
|
68
65
|
esac
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
touch "/tmp/architect-plan-reviewed-${SESSION_ID}"
|
|
67
|
+
[ "$VERDICT" = "PASS" ] && touch "/tmp/architect-plan-reviewed-${SESSION_ID}"
|
|
72
68
|
;;
|
|
73
69
|
esac
|
|
74
70
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const hookDir = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const role = "wr-architect:agent";
|
|
10
|
+
|
|
11
|
+
function response(input) {
|
|
12
|
+
if (typeof input.tool_response === "object" && input.tool_response) return input.tool_response;
|
|
13
|
+
try { return JSON.parse(input.tool_response); } catch { return {}; }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function riskDir(sessionId) {
|
|
17
|
+
return join(process.env.TMPDIR || "/tmp", `claude-risk-${sessionId}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function statePath(input, target) {
|
|
21
|
+
return join(riskDir(input.session_id), `codex-architect-${Buffer.from(target).toString("base64url")}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function remember(input) {
|
|
25
|
+
const target = response(input).agent_id ?? response(input).task_name;
|
|
26
|
+
if (typeof target !== "string" || !target) return;
|
|
27
|
+
mkdirSync(riskDir(input.session_id), { recursive: true });
|
|
28
|
+
rmSync(statePath(input, target), { force: true });
|
|
29
|
+
if (input.tool_input?.agent_type === role) writeFileSync(statePath(input, target), role, "utf8");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function complete(input) {
|
|
33
|
+
const target = input.tool_input?.target;
|
|
34
|
+
const output = response(input).previous_status?.completed;
|
|
35
|
+
if (typeof target !== "string" || typeof output !== "string") return;
|
|
36
|
+
const state = statePath(input, target);
|
|
37
|
+
if (!existsSync(state) || readFileSync(state, "utf8") !== role) return;
|
|
38
|
+
rmSync(state, { force: true });
|
|
39
|
+
const synthetic = {
|
|
40
|
+
...input,
|
|
41
|
+
tool_name: "Agent",
|
|
42
|
+
tool_input: { subagent_type: role },
|
|
43
|
+
tool_response: { content: [{ type: "text", text: output }] },
|
|
44
|
+
};
|
|
45
|
+
spawnSync(join(hookDir, "architect-mark-reviewed.sh"), {
|
|
46
|
+
cwd: input.cwd || process.cwd(),
|
|
47
|
+
env: process.env,
|
|
48
|
+
input: JSON.stringify(synthetic),
|
|
49
|
+
encoding: "utf8",
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let body = "";
|
|
54
|
+
process.stdin.setEncoding("utf8");
|
|
55
|
+
for await (const chunk of process.stdin) body += chunk;
|
|
56
|
+
let input;
|
|
57
|
+
try { input = JSON.parse(body); } catch { process.exit(0); }
|
|
58
|
+
if (!/^[A-Za-z0-9-]+$/.test(input.session_id || "")) process.exit(0);
|
|
59
|
+
|
|
60
|
+
if (["collaborationspawn_agent", "spawn_agent", "multi_agent_v1__spawn_agent"].includes(input.tool_name)) remember(input);
|
|
61
|
+
if (["collaborationinterrupt_agent", "close_agent", "multi_agent_v1__close_agent"].includes(input.tool_name)) complete(input);
|
package/hooks/hooks.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"hooks": {
|
|
3
3
|
"SessionStart": [
|
|
4
|
-
{ "matcher": "startup", "hooks": [
|
|
4
|
+
{ "matcher": "startup", "hooks": [
|
|
5
|
+
{ "type": "command", "command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/codex-agent.mjs --session-start" },
|
|
6
|
+
{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/architect-oversight-nudge.sh" }
|
|
7
|
+
] }
|
|
5
8
|
],
|
|
6
9
|
"UserPromptSubmit": [
|
|
7
10
|
{ "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/architect-detect.sh" }] },
|
|
@@ -15,6 +18,7 @@
|
|
|
15
18
|
],
|
|
16
19
|
"PostToolUse": [
|
|
17
20
|
{ "matcher": "Agent", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/architect-mark-reviewed.sh" }] },
|
|
21
|
+
{ "matcher": "collaborationspawn_agent|collaborationinterrupt_agent|spawn_agent|close_agent|multi_agent_v1__spawn_agent|multi_agent_v1__close_agent", "hooks": [{ "type": "command", "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/codex-agent-completion.mjs" }] },
|
|
18
22
|
{ "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/architect-refresh-hash.sh" }] },
|
|
19
23
|
{ "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/architect-compendium-update-entry.sh" }] },
|
|
20
24
|
{ "matcher": "Agent|Bash|Skill", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/architect-slide-marker.sh" }] }
|
|
@@ -78,22 +78,13 @@ No conflicts with existing decisions.")
|
|
|
78
78
|
# P181 bug-fix cases: substring-anywhere false-positive FAIL
|
|
79
79
|
# ---------------------------------------------------------------------------
|
|
80
80
|
|
|
81
|
-
@test "verdict-grep: marker
|
|
82
|
-
# Agent emits prose without a canonical heading but the narrative discusses
|
|
83
|
-
# the concept of ISSUES FOUND. Current substring grep falsely classifies
|
|
84
|
-
# this as FAIL → no marker. After fix: anchored regex doesn't match → falls
|
|
85
|
-
# through to default branch → marker drops (lockout-avoidance).
|
|
81
|
+
@test "verdict-grep: no marker without a canonical heading" {
|
|
86
82
|
INPUT=$(_make_input "I reviewed the change. The previous review surfaced ISSUES FOUND that have since been addressed; the current proposed change is fine.")
|
|
87
83
|
echo "$INPUT" | "$HOOK"
|
|
88
|
-
[ -f "$REVIEW_MARKER" ]
|
|
84
|
+
[ ! -f "$REVIEW_MARKER" ]
|
|
89
85
|
}
|
|
90
86
|
|
|
91
|
-
@test "verdict-grep:
|
|
92
|
-
# NEEDS DIRECTION is one of three canonical verdicts (agent.md line 137).
|
|
93
|
-
# It currently falls through to the default branch (creates marker for
|
|
94
|
-
# backward-compat lockout-avoidance). The bug: if the body narratively
|
|
95
|
-
# references the ISSUES FOUND verdict shape, substring grep fires FAIL.
|
|
96
|
-
# After fix: neither anchored regex matches → fallback creates marker.
|
|
87
|
+
@test "verdict-grep: NEEDS DIRECTION does not unlock edits" {
|
|
97
88
|
INPUT=$(_make_input "**Architecture Review: NEEDS DIRECTION**
|
|
98
89
|
|
|
99
90
|
A decision must be recorded. This differs from an ISSUES FOUND verdict because the option is not pinned.
|
|
@@ -101,7 +92,8 @@ A decision must be recorded. This differs from an ISSUES FOUND verdict because t
|
|
|
101
92
|
- Option A — ...
|
|
102
93
|
- Option B — ...")
|
|
103
94
|
echo "$INPUT" | "$HOOK"
|
|
104
|
-
[ -f "$REVIEW_MARKER" ]
|
|
95
|
+
[ ! -f "$REVIEW_MARKER" ]
|
|
96
|
+
[ ! -f "$PLAN_MARKER" ]
|
|
105
97
|
}
|
|
106
98
|
|
|
107
99
|
@test "verdict-grep: marker drops when PASS heading present and body also says 'ISSUES FOUND' inline" {
|
|
@@ -114,13 +106,8 @@ No conflicts. Note: earlier sessions reported ISSUES FOUND on adjacent files but
|
|
|
114
106
|
[ -f "$REVIEW_MARKER" ]
|
|
115
107
|
}
|
|
116
108
|
|
|
117
|
-
@test "verdict-grep:
|
|
118
|
-
# Verbatim substring "issues found" should not satisfy the anchored
|
|
119
|
-
# ISSUES FOUND regex (which requires the bold heading shape). Old code:
|
|
120
|
-
# grep -q "ISSUES FOUND" is case-sensitive so 'issues found' lowercase
|
|
121
|
-
# doesn't match either — this test pins case-sensitivity behaviour so
|
|
122
|
-
# future regex changes don't accidentally relax it.
|
|
109
|
+
@test "verdict-grep: prose-only approval does not unlock edits" {
|
|
123
110
|
INPUT=$(_make_input "Review complete — no issues found in the diff.")
|
|
124
111
|
echo "$INPUT" | "$HOOK"
|
|
125
|
-
[ -f "$REVIEW_MARKER" ]
|
|
112
|
+
[ ! -f "$REVIEW_MARKER" ]
|
|
126
113
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
|
|
3
|
+
setup() {
|
|
4
|
+
HOOK_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
5
|
+
TMP="$(mktemp -d)"
|
|
6
|
+
export TMPDIR="$TMP/runtime"
|
|
7
|
+
export CLAUDE_PROJECT_DIR="$TMP/project"
|
|
8
|
+
mkdir -p "$TMPDIR" "$CLAUDE_PROJECT_DIR/docs/decisions"
|
|
9
|
+
SESSION="architect-codex-$$"
|
|
10
|
+
TARGET="agent-target"
|
|
11
|
+
MARKER="/tmp/architect-reviewed-$SESSION"
|
|
12
|
+
HASH="$MARKER.hash"
|
|
13
|
+
PLAN="/tmp/architect-plan-reviewed-$SESSION"
|
|
14
|
+
rm -f "$MARKER" "$HASH" "$PLAN"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
teardown() {
|
|
18
|
+
rm -f "$MARKER" "$HASH" "$PLAN"
|
|
19
|
+
rm -rf "$TMP"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
dispatch() {
|
|
23
|
+
printf '%s' "$1" | node "$HOOK_DIR/codex-agent-completion.mjs"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
spawn() {
|
|
27
|
+
printf '{"session_id":"%s","cwd":"%s","tool_name":"multi_agent_v1__spawn_agent","tool_input":{"agent_type":"%s"},"tool_response":{"agent_id":"%s"}}' "$SESSION" "$CLAUDE_PROJECT_DIR" "$1" "$TARGET"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
close() {
|
|
31
|
+
printf '{"session_id":"%s","cwd":"%s","tool_name":"multi_agent_v1__close_agent","tool_input":{"target":"%s"},"tool_response":{"previous_status":{"completed":"%s"}}}' "$SESSION" "$CLAUDE_PROJECT_DIR" "$TARGET" "$1"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@test "matched Codex architect PASS creates review markers" {
|
|
35
|
+
dispatch "$(spawn wr-architect:agent)"
|
|
36
|
+
dispatch "$(close '**Architecture Review: PASS**')"
|
|
37
|
+
[ -f "$MARKER" ]
|
|
38
|
+
[ -f "$HASH" ]
|
|
39
|
+
[ -f "$PLAN" ]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@test "issues and malformed output fail closed" {
|
|
43
|
+
dispatch "$(spawn wr-architect:agent)"
|
|
44
|
+
dispatch "$(close '**Architecture Review: ISSUES FOUND**')"
|
|
45
|
+
[ ! -e "$MARKER" ]
|
|
46
|
+
dispatch "$(spawn wr-architect:agent)"
|
|
47
|
+
dispatch "$(close 'review complete')"
|
|
48
|
+
[ ! -e "$MARKER" ]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@test "unmatched close and non-architect target do not unlock" {
|
|
52
|
+
dispatch "$(close '**Architecture Review: PASS**')"
|
|
53
|
+
[ ! -e "$MARKER" ]
|
|
54
|
+
dispatch "$(spawn default)"
|
|
55
|
+
dispatch "$(close '**Architecture Review: PASS**')"
|
|
56
|
+
[ ! -e "$MARKER" ]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@test "reused target clears stale architect identity" {
|
|
60
|
+
dispatch "$(spawn wr-architect:agent)"
|
|
61
|
+
dispatch "$(spawn default)"
|
|
62
|
+
dispatch "$(close '**Architecture Review: PASS**')"
|
|
63
|
+
[ ! -e "$MARKER" ]
|
|
64
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windyroad/architect",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"description": "Architecture decision enforcement for AI coding agents",
|
|
5
5
|
"bin": {
|
|
6
6
|
"windyroad-architect": "./bin/install.mjs"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"prepack": "node scripts/sync-codex-skills.mjs --pack",
|
|
11
|
+
"postpack": "node scripts/sync-codex-skills.mjs --restore-pack"
|
|
12
|
+
},
|
|
9
13
|
"license": "MIT",
|
|
10
14
|
"repository": {
|
|
11
15
|
"type": "git",
|
|
@@ -24,6 +28,7 @@
|
|
|
24
28
|
"hooks/",
|
|
25
29
|
"skills/",
|
|
26
30
|
"scripts/",
|
|
31
|
+
".agents/",
|
|
27
32
|
".claude-plugin/",
|
|
28
33
|
".codex-plugin/",
|
|
29
34
|
"lib/",
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { dirname, join, resolve } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
|
+
const source = join(packageRoot, "agents", "agent.md");
|
|
11
|
+
const filename = "wr-architect-agent.toml";
|
|
12
|
+
const owner = "# Generated by @windyroad/architect from agents/agent.md.";
|
|
13
|
+
|
|
14
|
+
function split(markdown) {
|
|
15
|
+
const end = markdown.indexOf("\n---\n", 4);
|
|
16
|
+
return markdown.startsWith("---\n") && end !== -1
|
|
17
|
+
? { frontmatter: markdown.slice(4, end), body: markdown.slice(end + 5) }
|
|
18
|
+
: { frontmatter: "", body: markdown };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function description(frontmatter) {
|
|
22
|
+
const lines = frontmatter.split(/\r?\n/);
|
|
23
|
+
const start = lines.findIndex((line) => line.startsWith("description:"));
|
|
24
|
+
if (start === -1) return "Architecture reviewer for structural and technology decisions.";
|
|
25
|
+
const value = [lines[start].slice("description:".length).trim()];
|
|
26
|
+
for (let index = start + 1; index < lines.length && /^\s+/.test(lines[index]); index += 1) {
|
|
27
|
+
value.push(lines[index].trim());
|
|
28
|
+
}
|
|
29
|
+
return value.filter(Boolean).join(" ");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function payload() {
|
|
33
|
+
const { frontmatter, body } = split(readFileSync(source, "utf8"));
|
|
34
|
+
return [
|
|
35
|
+
"# Do not edit by hand; update agents/agent.md and reinstall.",
|
|
36
|
+
'name = "wr-architect:agent"',
|
|
37
|
+
`description = ${JSON.stringify(description(frontmatter))}`,
|
|
38
|
+
'sandbox_mode = "read-only"',
|
|
39
|
+
'developer_instructions = """',
|
|
40
|
+
body.replace(/\\/g, "\\\\").replace(/"""/g, '\\"\\"\\"').trimEnd(),
|
|
41
|
+
'"""',
|
|
42
|
+
"",
|
|
43
|
+
].join("\n");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function renderArchitectAgent() {
|
|
47
|
+
const content = payload();
|
|
48
|
+
const hash = createHash("sha256").update(content).digest("hex");
|
|
49
|
+
return `${owner}\n# Generated content SHA-256: ${hash}\n${content}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function owned(content) {
|
|
53
|
+
if (!content.startsWith(`${owner}\n`)) return false;
|
|
54
|
+
const lines = content.split("\n");
|
|
55
|
+
const match = lines[1]?.match(/^# Generated content SHA-256: ([0-9a-f]{64})$/);
|
|
56
|
+
return Boolean(match && createHash("sha256").update(lines.slice(2).join("\n")).digest("hex") === match[1]);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function agentDir(scope, cwd = process.cwd(), env = process.env) {
|
|
60
|
+
return scope === "user"
|
|
61
|
+
? join(env.CODEX_HOME || join(homedir(), ".codex"), "agents")
|
|
62
|
+
: join(cwd, ".codex", "agents");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function installArchitectAgent(targetDir, { quiet = false } = {}) {
|
|
66
|
+
mkdirSync(targetDir, { recursive: true });
|
|
67
|
+
const target = join(targetDir, filename);
|
|
68
|
+
const expected = renderArchitectAgent();
|
|
69
|
+
if (existsSync(target)) {
|
|
70
|
+
const current = readFileSync(target, "utf8");
|
|
71
|
+
if (current === expected) return false;
|
|
72
|
+
if (!owned(current)) {
|
|
73
|
+
if (!quiet) console.log(`Preserved user-managed Codex agent at ${target}.`);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
writeFileSync(target, expected, "utf8");
|
|
78
|
+
if (!quiet) console.log(`Codex architect agent installed at ${target}.`);
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function uninstallArchitectAgent(targetDir) {
|
|
83
|
+
const target = join(targetDir, filename);
|
|
84
|
+
if (existsSync(target) && owned(readFileSync(target, "utf8"))) rmSync(target);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
88
|
+
if (process.argv.includes("--session-start") && !process.env.CODEX_THREAD_ID) process.exit(0);
|
|
89
|
+
const scopeIndex = process.argv.indexOf("--scope");
|
|
90
|
+
const scope = scopeIndex === -1 ? (process.argv.includes("--session-start") ? "user" : "project") : process.argv[scopeIndex + 1];
|
|
91
|
+
const target = agentDir(scope);
|
|
92
|
+
if (process.argv.includes("--uninstall")) uninstallArchitectAgent(target);
|
|
93
|
+
else {
|
|
94
|
+
const changed = installArchitectAgent(target, { quiet: process.argv.includes("--session-start") });
|
|
95
|
+
if (changed && process.argv.includes("--session-start")) {
|
|
96
|
+
console.log(JSON.stringify({ systemMessage: "wr-architect: Codex agent installed; restart Codex to activate it." }));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
cpSync,
|
|
5
|
+
existsSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
renameSync,
|
|
9
|
+
rmSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
} from "node:fs";
|
|
12
|
+
import { dirname, join, resolve } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
|
|
15
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
16
|
+
const skillsRoot = join(packageRoot, "skills");
|
|
17
|
+
const backupRoot = join(packageRoot, ".pack-claude-skills");
|
|
18
|
+
|
|
19
|
+
const preamble = `<!-- Generated from the Claude skill source during npm pack. -->
|
|
20
|
+
|
|
21
|
+
> Codex runtime note: use \`request_user_input\` in Plan Mode for structured
|
|
22
|
+
> questions. Resolve \`<architect-plugin-root>\` from this installed
|
|
23
|
+
> \`SKILL.md\` path: it is two directories above the skill directory. Replace
|
|
24
|
+
> that token with the absolute path before running a bundled script; never
|
|
25
|
+
> search the adopter repository or rely on a \`wr-architect-*\` command being
|
|
26
|
+
> on \`PATH\`. Spawn the installed \`wr-architect:agent\` custom agent with the
|
|
27
|
+
> native Codex subagent tool, wait for it, and close the same agent.
|
|
28
|
+
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const commands = new Map([
|
|
32
|
+
["wr-architect-detect-unoversighted", "bash \"<architect-plugin-root>/scripts/detect-unoversighted.sh\""],
|
|
33
|
+
["wr-architect-generate-decisions-compendium", "bash \"<architect-plugin-root>/scripts/generate-decisions-compendium.sh\""],
|
|
34
|
+
["wr-architect-is-decision-unconfirmed", "bash \"<architect-plugin-root>/scripts/is-decision-unconfirmed.sh\""],
|
|
35
|
+
["wr-architect-mark-oversight-confirmed", "bash \"<architect-plugin-root>/scripts/mark-oversight-confirmed.sh\""],
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
function transform(text) {
|
|
39
|
+
let result = text.replaceAll("AskUserQuestion", "request_user_input");
|
|
40
|
+
for (const [command, replacement] of commands) {
|
|
41
|
+
result = result.replaceAll(command, replacement);
|
|
42
|
+
}
|
|
43
|
+
result = result.replaceAll("packages/architect/", "<architect-plugin-root>/");
|
|
44
|
+
result = result.replace(
|
|
45
|
+
"is a `$PATH`-resolved shim (ADR-049 naming grammar) dispatching `<architect-plugin-root>/scripts/",
|
|
46
|
+
"is the bundled Codex script at `<architect-plugin-root>/scripts/",
|
|
47
|
+
);
|
|
48
|
+
if (!result.startsWith("---\n")) return preamble + result;
|
|
49
|
+
const end = result.indexOf("\n---\n", 4);
|
|
50
|
+
return end === -1
|
|
51
|
+
? preamble + result
|
|
52
|
+
: result.slice(0, end + 5) + "\n" + preamble + result.slice(end + 5);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function skillFiles(root) {
|
|
56
|
+
return readdirSync(root, { withFileTypes: true })
|
|
57
|
+
.filter((entry) => entry.isDirectory())
|
|
58
|
+
.map((entry) => join(root, entry.name, "SKILL.md"))
|
|
59
|
+
.filter(existsSync);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (process.argv.includes("--restore-pack")) {
|
|
63
|
+
if (existsSync(backupRoot)) {
|
|
64
|
+
rmSync(skillsRoot, { recursive: true, force: true });
|
|
65
|
+
renameSync(backupRoot, skillsRoot);
|
|
66
|
+
console.log("Restored Claude architect skill source after pack.");
|
|
67
|
+
}
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!process.argv.includes("--pack")) {
|
|
72
|
+
console.error("Usage: sync-codex-skills.mjs --pack | --restore-pack");
|
|
73
|
+
process.exit(2);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (existsSync(backupRoot)) {
|
|
77
|
+
console.error(`Refusing to pack: backup already exists at ${backupRoot}`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
renameSync(skillsRoot, backupRoot);
|
|
82
|
+
cpSync(backupRoot, skillsRoot, { recursive: true });
|
|
83
|
+
const files = skillFiles(skillsRoot);
|
|
84
|
+
for (const file of files) writeFileSync(file, transform(readFileSync(file, "utf8")), "utf8");
|
|
85
|
+
console.log(`Packed ${files.length} Codex-facing architect skill file(s).`);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env bats
|
|
2
|
+
|
|
3
|
+
setup() {
|
|
4
|
+
unset CODEX_THREAD_ID
|
|
5
|
+
PACKAGE="$(cd "$(dirname "$BATS_TEST_FILENAME")/../.." && pwd)"
|
|
6
|
+
TMP="$(mktemp -d)"
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@test "agent scope selects project or user directory" {
|
|
10
|
+
mkdir -p "$TMP/project"
|
|
11
|
+
(cd "$TMP/project" && node "$PACKAGE/scripts/codex-agent.mjs" --scope project >/dev/null)
|
|
12
|
+
[ -f "$TMP/project/.codex/agents/wr-architect-agent.toml" ]
|
|
13
|
+
|
|
14
|
+
CODEX_HOME="$TMP/home" node "$PACKAGE/scripts/codex-agent.mjs" --scope user >/dev/null
|
|
15
|
+
[ -f "$TMP/home/agents/wr-architect-agent.toml" ]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@test "SessionStart repairs only Codex user registration" {
|
|
19
|
+
CODEX_HOME="$TMP/claude-home" node "$PACKAGE/scripts/codex-agent.mjs" --session-start
|
|
20
|
+
[ ! -d "$TMP/claude-home/agents" ]
|
|
21
|
+
|
|
22
|
+
run env CODEX_THREAD_ID=test CODEX_HOME="$TMP/codex-home" node "$PACKAGE/scripts/codex-agent.mjs" --session-start
|
|
23
|
+
[ "$status" -eq 0 ]
|
|
24
|
+
[[ "$output" == *"restart Codex"* ]]
|
|
25
|
+
[ -f "$TMP/codex-home/agents/wr-architect-agent.toml" ]
|
|
26
|
+
|
|
27
|
+
run env CODEX_THREAD_ID=test CODEX_HOME="$TMP/codex-home" node "$PACKAGE/scripts/codex-agent.mjs" --session-start
|
|
28
|
+
[ "$status" -eq 0 ]
|
|
29
|
+
[ -z "$output" ]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@test "default installer remains Claude-only" {
|
|
33
|
+
run node "$PACKAGE/bin/install.mjs" --dry-run
|
|
34
|
+
[ "$status" -eq 0 ]
|
|
35
|
+
[[ "$output" == *"claude plugin marketplace add"* ]]
|
|
36
|
+
[[ "$output" != *"codex plugin marketplace add"* ]]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@test "packed installer registers plugin and exact agent in isolated Codex home" {
|
|
40
|
+
run npm pack "$PACKAGE" --pack-destination "$TMP"
|
|
41
|
+
[ "$status" -eq 0 ]
|
|
42
|
+
export CODEX_HOME="$TMP/codex-installed"
|
|
43
|
+
run npm exec --yes --package "$TMP"/*.tgz -- windyroad-architect --runtime codex --scope user
|
|
44
|
+
[ "$status" -eq 0 ]
|
|
45
|
+
[ -f "$CODEX_HOME/agents/wr-architect-agent.toml" ]
|
|
46
|
+
run codex plugin list
|
|
47
|
+
[ "$status" -eq 0 ]
|
|
48
|
+
[[ "$output" == *"wr-architect@windyroad-architect-local"* ]]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
teardown() {
|
|
52
|
+
node "$PACKAGE/scripts/sync-codex-skills.mjs" --restore-pack >/dev/null 2>&1 || true
|
|
53
|
+
rm -rf "$TMP"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@test "npm pack emits Codex skills and restores Claude sources" {
|
|
57
|
+
before="$(shasum -a 256 "$PACKAGE"/skills/*/SKILL.md)"
|
|
58
|
+
run npm pack "$PACKAGE" --pack-destination "$TMP"
|
|
59
|
+
[ "$status" -eq 0 ]
|
|
60
|
+
[ "$before" = "$(shasum -a 256 "$PACKAGE"/skills/*/SKILL.md)" ]
|
|
61
|
+
|
|
62
|
+
tar -xzf "$TMP"/*.tgz -C "$TMP"
|
|
63
|
+
run grep -F 'bash "<architect-plugin-root>/scripts/generate-decisions-compendium.sh"' "$TMP/package/skills/review-decisions/SKILL.md"
|
|
64
|
+
[ "$status" -eq 0 ]
|
|
65
|
+
run grep -F 'use `request_user_input`' "$TMP/package/skills/review-decisions/SKILL.md"
|
|
66
|
+
[ "$status" -eq 0 ]
|
|
67
|
+
run grep -F 'wr-architect-generate-decisions-compendium' "$TMP/package/skills/review-decisions/SKILL.md"
|
|
68
|
+
[ "$status" -ne 0 ]
|
|
69
|
+
run grep -F 'packages/architect/' "$TMP/package/skills/create-adr/SKILL.md"
|
|
70
|
+
[ "$status" -ne 0 ]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@test "Codex agent install is exact, owned, and removable" {
|
|
74
|
+
export CODEX_HOME="$TMP/codex"
|
|
75
|
+
run node "$PACKAGE/scripts/codex-agent.mjs" --scope user
|
|
76
|
+
[ "$status" -eq 0 ]
|
|
77
|
+
target="$CODEX_HOME/agents/wr-architect-agent.toml"
|
|
78
|
+
grep -Fq 'name = "wr-architect:agent"' "$target"
|
|
79
|
+
|
|
80
|
+
printf '# user managed\n' > "$target"
|
|
81
|
+
node "$PACKAGE/scripts/codex-agent.mjs" --scope user >/dev/null
|
|
82
|
+
[ "$(cat "$target")" = "# user managed" ]
|
|
83
|
+
|
|
84
|
+
node "$PACKAGE/scripts/codex-agent.mjs" --scope user --uninstall
|
|
85
|
+
[ -e "$target" ]
|
|
86
|
+
}
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wr-architect:capture-adr
|
|
3
|
-
description: Lightweight ADR-capture skill for aside-invocation during foreground work — derives full MADR substance (Considered Options / Decision Drivers / Consequences / Confirmation / Reassessment) silently from the in-session decision context, single commit, no inline architect-review handoff, no
|
|
3
|
+
description: Lightweight ADR-capture skill for aside-invocation during foreground work — derives full MADR substance (Considered Options / Decision Drivers / Consequences / Confirmation / Reassessment) silently from the in-session decision context, single commit, no inline architect-review handoff, no request_user_input. Lightweight means zero-interaction + single-commit, not skimpy content (RFC-045). Use this when the user (or agent mid-iter) wants to record a decision quickly without the ~10-15 turn ceremony of /wr-architect:create-adr. For interactive full-intake new ADR creation where the user authors the options + drivers + consequences + confirmation, use /wr-architect:create-adr.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Bash, Grep, Glob
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
<!-- Generated from the Claude skill source during npm pack. -->
|
|
8
|
+
|
|
9
|
+
> Codex runtime note: use `request_user_input` in Plan Mode for structured
|
|
10
|
+
> questions. Resolve `<architect-plugin-root>` from this installed
|
|
11
|
+
> `SKILL.md` path: it is two directories above the skill directory. Replace
|
|
12
|
+
> that token with the absolute path before running a bundled script; never
|
|
13
|
+
> search the adopter repository or rely on a `wr-architect-*` command being
|
|
14
|
+
> on `PATH`. Spawn the installed `wr-architect:agent` custom agent with the
|
|
15
|
+
> native Codex subagent tool, wait for it, and close the same agent.
|
|
16
|
+
|
|
17
|
+
|
|
7
18
|
# Capture ADR Skill
|
|
8
19
|
|
|
9
20
|
Capture an Architecture Decision Record quickly during foreground work. Lightweight aside-invocation surface that complements the heavyweight `/wr-architect:create-adr` flow. See `REFERENCE.md` in this directory for rationale, edge cases, contract trade-offs, and the ADR-032 foreground-lightweight-capture amendment.
|
|
@@ -17,13 +28,13 @@ This skill is the foreground-lightweight-capture variant of `/wr-architect:creat
|
|
|
17
28
|
- **User-driven design conversations**: user resolves options (a)/(b)/(c) during conversational work; today the settlement gets buried in a problem-ticket RCA section instead of codified.
|
|
18
29
|
|
|
19
30
|
**Use `/wr-architect:create-adr` instead** when:
|
|
20
|
-
- The user wants to walk the full interactive intake flow and author the sections themselves (Considered Options ≥2, Decision Drivers, full Consequences, Confirmation criteria, Pros/Cons of Options via
|
|
31
|
+
- The user wants to walk the full interactive intake flow and author the sections themselves (Considered Options ≥2, Decision Drivers, full Consequences, Confirmation criteria, Pros/Cons of Options via request_user_input).
|
|
21
32
|
- The decision is contested or under-specified in-session — silent derivation needs a real decision context to derive FROM; if the options were never actually weighed, create-adr's interactive intake is the honest surface.
|
|
22
33
|
- The decision needs immediate architect review + acceptance (capture-adr writes `.proposed.md`; acceptance review is a follow-up via `/wr-architect:create-adr` or direct architect-agent review).
|
|
23
34
|
|
|
24
35
|
## Rule 6 audit (per ADR-032 + ADR-013)
|
|
25
36
|
|
|
26
|
-
This skill has **zero
|
|
37
|
+
This skill has **zero request_user_input branches** by design. Each potentially-interactive decision is framework-mediated per ADR-044:
|
|
27
38
|
|
|
28
39
|
| Decision | Resolution |
|
|
29
40
|
|----------|-----------|
|
|
@@ -168,7 +179,7 @@ Single `Write` to `docs/decisions/<NNN>-<kebab-title>.proposed.md`.
|
|
|
168
179
|
After the ADR lands, regenerate `docs/decisions/README.md` so the architect-agent routine load surface includes the new entry:
|
|
169
180
|
|
|
170
181
|
```bash
|
|
171
|
-
|
|
182
|
+
bash "<architect-plugin-root>/scripts/generate-decisions-compendium.sh"
|
|
172
183
|
```
|
|
173
184
|
|
|
174
185
|
The compendium is the architect agent's primary load surface per ADR-077; capture-adr owns keeping it fresh (skills + agent are PRIMARY; the `architect-compendium-refresh-discipline.sh` hook is the safety-net backstop). The next step stages both files together.
|
|
@@ -206,21 +217,21 @@ The trailing pointer is **not optional** — it is the user-visible signal that
|
|
|
206
217
|
|
|
207
218
|
**Confirm-every-ADR gate (ADR-064):** a capture-adr ADR is recorded `proposed` with derived substance but WITHOUT human review of that substance. It must NOT be promoted to `accepted` until a human has ratified the derived content via `/wr-architect:review-decisions` (or a `/wr-architect:create-adr` review-and-confirm pass). Capture records the decision quickly; the ratification — not the capture — is what gives it human oversight. This is prong 1 of P283 (lift auto-/quick-recorded decisions to human-confirmed before they stand).
|
|
208
219
|
|
|
209
|
-
**Oversight marker discipline (ADR-066 amendment 2026-06-02 / P348).** A capture-adr ADR MUST be born `human-oversight: unconfirmed` — NOT `confirmed`. Capture is the AFK-friendly aside surface; there is no substance-confirm `
|
|
220
|
+
**Oversight marker discipline (ADR-066 amendment 2026-06-02 / P348).** A capture-adr ADR MUST be born `human-oversight: unconfirmed` — NOT `confirmed`. Capture is the AFK-friendly aside surface; there is no substance-confirm `request_user_input` pass in this flow, so `confirmed` would be a hollow marker (the P348 bug class). The `architect-oversight-marker-discipline.sh` PreToolUse hook will DENY any Edit/Write that introduces `human-oversight: confirmed` without a matching session-scoped evidence marker. The frontmatter (Step 3 above) MUST include `human-oversight: unconfirmed` so the ADR enters the world honestly self-identified as needing user confirmation. The drain (`/wr-architect:review-decisions`) and a `/wr-architect:create-adr <NNN>` review pass are the surfaces that legitimately promote it to `confirmed` via `bash "<architect-plugin-root>/scripts/mark-oversight-confirmed.sh"` + the gated marker write.
|
|
210
221
|
|
|
211
222
|
## Composition with create-adr
|
|
212
223
|
|
|
213
224
|
| Concern | create-adr | capture-adr |
|
|
214
225
|
|---------|------------|-------------|
|
|
215
|
-
| Considered Options |
|
|
216
|
-
| Decision Drivers |
|
|
217
|
-
| Consequences |
|
|
218
|
-
| Confirmation |
|
|
219
|
-
| Reassessment criteria |
|
|
226
|
+
| Considered Options | request_user_input gathering ≥2 options + pros/cons (user authors) | Silent derivation of chosen + actually-rejected alternatives (agent authors, human ratifies at drain) |
|
|
227
|
+
| Decision Drivers | request_user_input gathering | Silent derivation from decision context |
|
|
228
|
+
| Consequences | request_user_input gathering Good/Neutral/Bad | Silent derivation — real Good/Neutral/Bad trade-off analysis at capture |
|
|
229
|
+
| Confirmation | request_user_input gathering testable criteria | Silent derivation of testable criteria |
|
|
230
|
+
| Reassessment criteria | request_user_input gathering | Silent derivation + 3-month default date |
|
|
220
231
|
| Frontmatter | Full populated frontmatter | Derived values (git user.name etc.) — no sentinels |
|
|
221
|
-
| Decision-boundary check (Step 2b) | Multi-decision split via
|
|
232
|
+
| Decision-boundary check (Step 2b) | Multi-decision split via request_user_input | Out of scope (one ADR per invocation) |
|
|
222
233
|
| Supersession (Step 6) | Handles `git mv .accepted.md → .superseded.md` | Out of scope (capture is creation only) |
|
|
223
|
-
| Confirm-with-user (Step 5) |
|
|
234
|
+
| Confirm-with-user (Step 5) | request_user_input review pass at intake | Deferred to the self-firing oversight drain (`human-oversight: unconfirmed` → SessionStart nudge → `/wr-architect:review-decisions`) |
|
|
224
235
|
| Commit grain | One commit per intake | One commit per capture |
|
|
225
236
|
| Use case | Full-intake new ADR; user wants to author the flow interactively | Aside-invocation; capture-and-continue |
|
|
226
237
|
|
|
@@ -237,7 +248,7 @@ The two skills share the `docs/decisions/*.proposed.md` directory and the next-I
|
|
|
237
248
|
- **ADR-044** — decision-delegation contract (framework-mediated mechanical-stage carve-outs).
|
|
238
249
|
- **ADR-049** — bin/ on PATH (capture-adr is self-contained; no shim required, same as create-adr).
|
|
239
250
|
- **ADR-052** — behavioural-tests-default for skill testing.
|
|
240
|
-
-
|
|
241
|
-
-
|
|
251
|
+
- `<architect-plugin-root>/skills/create-adr/SKILL.md` — heavyweight intake counterpart.
|
|
252
|
+
- `<architect-plugin-root>/agents/agent.md` — wr-architect:agent review surface; reviews `.proposed.md` ADRs at acceptance delegation.
|
|
242
253
|
|
|
243
254
|
$ARGUMENTS
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wr-architect:create-adr
|
|
3
3
|
description: Create a new Architecture Decision Record (MADR 4.0) in docs/decisions/. Examines existing decisions, asks about the problem and options, and writes a properly formatted ADR.
|
|
4
|
-
allowed-tools: Read, Write, Edit, Bash, Glob, Grep,
|
|
4
|
+
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, request_user_input
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
<!-- Generated from the Claude skill source during npm pack. -->
|
|
8
|
+
|
|
9
|
+
> Codex runtime note: use `request_user_input` in Plan Mode for structured
|
|
10
|
+
> questions. Resolve `<architect-plugin-root>` from this installed
|
|
11
|
+
> `SKILL.md` path: it is two directories above the skill directory. Replace
|
|
12
|
+
> that token with the absolute path before running a bundled script; never
|
|
13
|
+
> search the adopter repository or rely on a `wr-architect-*` command being
|
|
14
|
+
> on `PATH`. Spawn the installed `wr-architect:agent` custom agent with the
|
|
15
|
+
> native Codex subagent tool, wait for it, and close the same agent.
|
|
16
|
+
|
|
17
|
+
|
|
7
18
|
# Architecture Decision Record Generator
|
|
8
19
|
|
|
9
20
|
Create a new ADR in `docs/decisions/` following MADR 4.0 format. The wr-architect:agent reviews these files to enforce architectural compliance.
|
|
10
21
|
|
|
11
22
|
## Needs-Direction handoff + confirm-every-ADR (ADR-064)
|
|
12
23
|
|
|
13
|
-
When a `wr-architect:agent` review returns a **NEEDS DIRECTION** verdict (a new decision with 2+ viable options and no pinned direction, per ADR-064), the option choice is the user's, not the agent's — this skill is the translation surface. The architect's named question + options become the Step 2 cat-1 `
|
|
24
|
+
When a `wr-architect:agent` review returns a **NEEDS DIRECTION** verdict (a new decision with 2+ viable options and no pinned direction, per ADR-064), the option choice is the user's, not the agent's — this skill is the translation surface. The architect's named question + options become the Step 2 cat-1 `request_user_input` calls (Considered Options / Decision Outcome), and the Step 5 confirm is the load-bearing **review-and-confirm-every-ADR** gate: an ADR must not stand as a human-oversighted decision (reach `accepted`) without that confirm pass. A `/wr-architect:capture-adr` ADR — zero-ask, with its decision pre-pinned in `$ARGUMENTS` and its remaining sections silently DERIVED at capture per the ADR-032 derived-substance amendment (RFC-045) — must still have its derived substance human-ratified (via `/wr-architect:review-decisions` or this skill's confirm) before promotion to `accepted`. When direction IS already pinned (same-turn / same-session / accepted ADR / RISK-POLICY.md / CLAUDE.md mandatory rule), act on it — do not re-ask (P132 inverse-P078 guard).
|
|
14
25
|
|
|
15
26
|
## Steps
|
|
16
27
|
|
|
@@ -24,34 +35,34 @@ Scan for existing ADRs:
|
|
|
24
35
|
|
|
25
36
|
### 2. Gather context (P132 derive-first; ADR-044 category-4 silent-framework on derivable fields; category-1 direction-setting only on user-judgment fields)
|
|
26
37
|
|
|
27
|
-
**Shared dispatch helper**: this surface invokes
|
|
38
|
+
**Shared dispatch helper**: this surface invokes `<architect-plugin-root>/lib/derive-first-dispatch.sh` for the canonical slug derivation (Title) and I2-isomorphic stderr advisory format. The canonical source-of-truth lives at `packages/shared/derive-first-dispatch.sh`; the architect package carries a synced per-package copy at `<architect-plugin-root>/lib/derive-first-dispatch.sh` per ADR-017 (Shared code duplicated into per-package lib/ kept in sync). The same helper is sourced by `/wr-itil:capture-problem` Step 1.5, `/wr-itil:manage-incident` Step 4, and `/wr-itil:manage-problem` Step 4 (each from its own per-package `packages/itil/lib/` copy); drift in the advisory shape across the four surfaces re-opens P132.
|
|
28
39
|
|
|
29
|
-
**Derive-first dispatch.** ADR creation is fundamentally user-judgment-bound — only the user knows the decision space, the alternatives considered, and the chosen-option rationale. But the **declaration-skeleton fields** (Title, status, date, reassessment-date, context-and-problem-statement) carry observable evidence in the user's prose, the working tree, and the wall-clock — the framework can resolve them without firing `
|
|
40
|
+
**Derive-first dispatch.** ADR creation is fundamentally user-judgment-bound — only the user knows the decision space, the alternatives considered, and the chosen-option rationale. But the **declaration-skeleton fields** (Title, status, date, reassessment-date, context-and-problem-statement) carry observable evidence in the user's prose, the working tree, and the wall-clock — the framework can resolve them without firing `request_user_input`. The retained `request_user_input` surfaces (Decision Drivers, Considered Options, Decision Outcome, Consequences, Confirmation, decision-makers) are the genuine **category-1 direction-setting** fields.
|
|
30
41
|
|
|
31
42
|
The P132 inverse-P078 trap (`docs/problems/known-error/132-...md`) is the load-bearing motivation. create-adr Step 2 is the **fourth declaration-skill surface** under Phase 2a to ship the derive-first dispatch (after `/wr-itil:capture-problem` Step 1.5, `/wr-itil:manage-incident` Step 4, and `/wr-itil:manage-problem` Step 4). The pattern is I2-isomorphic across all four — the stderr advisory shape `<skill>: derived <field>=<value> from <source>; <reversibility>` is identical beyond substituted values per the helper's `emit_stderr_advisory` function (architect verdict 2026-05-16 P132 Phase 2a-iii-B: pattern lock-in across the 4-surface set).
|
|
32
43
|
|
|
33
|
-
Resolve each field via the following dispatch. **The order is load-bearing** — every derivable field resolves silently with a stderr advisory citing the source; only user-judgment fields fire `
|
|
44
|
+
Resolve each field via the following dispatch. **The order is load-bearing** — every derivable field resolves silently with a stderr advisory citing the source; only user-judgment fields fire `request_user_input`.
|
|
34
45
|
|
|
35
46
|
| Field | Dispatch | ADR-044 category |
|
|
36
47
|
|-------|----------|------------------|
|
|
37
|
-
| **Title** | Derive silently. Kebab-case the first 8-10 non-stopword tokens of the user's prose problem-statement (same slug derivation as `/wr-itil:capture-problem` Step 1.4, `/wr-itil:manage-incident` Step 4, and `/wr-itil:manage-problem` Step 4 — uses the shared helper's `derive_kebab_slug` function). At intake the derived slug typically encodes the **question** (the problem-statement is question-shaped); the title-as-outcome convention in Step 2a below names the GOOD/BAD shapes, and Step 5a's mechanical retitle-after-decision check renames the file to the chosen-option's outcome shape after substance-confirm passes. Emit stderr advisory: `create-adr: derived title='<slug>' from problem-statement; re-invoke with the desired title or rename the file if the slug is wrong`. Do NOT fire
|
|
48
|
+
| **Title** | Derive silently. Kebab-case the first 8-10 non-stopword tokens of the user's prose problem-statement (same slug derivation as `/wr-itil:capture-problem` Step 1.4, `/wr-itil:manage-incident` Step 4, and `/wr-itil:manage-problem` Step 4 — uses the shared helper's `derive_kebab_slug` function). At intake the derived slug typically encodes the **question** (the problem-statement is question-shaped); the title-as-outcome convention in Step 2a below names the GOOD/BAD shapes, and Step 5a's mechanical retitle-after-decision check renames the file to the chosen-option's outcome shape after substance-confirm passes. Emit stderr advisory: `create-adr: derived title='<slug>' from problem-statement; re-invoke with the desired title or rename the file if the slug is wrong`. Do NOT fire request_user_input. | category-4 silent-framework |
|
|
38
49
|
| **status** (frontmatter) | Always `proposed` for new ADRs per Step 4 template convention. No ask, no advisory needed — SKILL convention is unambiguous. | category-4 silent-framework |
|
|
39
50
|
| **date** (frontmatter) | Today's date (`date +%Y-%m-%d`) per Step 4 template. No ask, no advisory needed — wall-clock derivation is unambiguous. | category-4 silent-framework |
|
|
40
51
|
| **reassessment-date** (frontmatter) | Today + 3 months (`date -v+3m +%Y-%m-%d` on BSD-date / `date -d '+3 months' +%Y-%m-%d` on GNU-date) per Step 4 template. Emit stderr advisory: `create-adr: derived reassessment-date='<YYYY-MM-DD>' from today+3-months default; re-invoke with --reassessment-date= or edit the frontmatter to override`. | category-4 silent-framework |
|
|
41
|
-
| **Context and Problem Statement** | Pull verbatim from `$ARGUMENTS` prose into the Step 4 template's `## Context and Problem Statement` section. **Fallback**: when `$ARGUMENTS` carries NO problem prose (only flags or empty body), fire
|
|
42
|
-
| **decision-makers** | Retain
|
|
43
|
-
| **Decision Drivers** | Retain
|
|
44
|
-
| **Considered Options** | Retain
|
|
45
|
-
| **Decision Outcome** / **Rationale** | Retain
|
|
46
|
-
| **Consequences** (Good / Neutral / Bad) | Retain
|
|
47
|
-
| **Confirmation** | Retain
|
|
48
|
-
| **consulted** / **informed** (frontmatter) | Default to empty list per Step 4 template; fold into the decision-makers
|
|
52
|
+
| **Context and Problem Statement** | Pull verbatim from `$ARGUMENTS` prose into the Step 4 template's `## Context and Problem Statement` section. **Fallback**: when `$ARGUMENTS` carries NO problem prose (only flags or empty body), fire request_user_input as the genuine category-1 direction-setting surface — *"only the user knows the problem being solved."* Question text: *"What problem does this ADR solve? Why is a decision needed now?"* This is the prose-fallback path; the typical maintainer invocation carries the problem-statement in arguments. | category-1 direction-setting (fallback only; category-4 silent-framework on the typical path where prose is present) |
|
|
53
|
+
| **decision-makers** | Retain request_user_input. Architect verdict 2026-05-16: silent derivation from `git config user.name` would conflate "who committed the ADR" with "who made the decision" — a multi-party decision is one of the canonical mis-attribution risks ADR-013's identity model rejects. Once-per-ADR ask is low-friction in absolute terms. Question text: *"Who are the decision-makers?"* | category-1 direction-setting |
|
|
54
|
+
| **Decision Drivers** | Retain request_user_input. Only the user knows which factors weighted the decision. This is the create-adr-equivalent of manage-problem Step 4's Description (the user-judgment surface). | category-1 direction-setting |
|
|
55
|
+
| **Considered Options** | Retain request_user_input. Only the user knows the alternatives evaluated. ADR-044 cat-5 (taste) would only apply if the framework could offer 2+ valid options — but the alternative space is genuinely user-knowledge (the framework can offer "do nothing" + a status-quo option but the actual alternatives are the user's). Architect verdict 2026-05-16: confirmed cat-1 over cat-5. Per MADR 4.0: ≥2 alternatives including "do nothing" where applicable. | category-1 direction-setting |
|
|
56
|
+
| **Decision Outcome** / **Rationale** | Retain request_user_input. The chosen option + primary reason for the choice. | category-1 direction-setting |
|
|
57
|
+
| **Consequences** (Good / Neutral / Bad) | Retain request_user_input. Only the user knows the expected consequences of the decision. | category-1 direction-setting |
|
|
58
|
+
| **Confirmation** | Retain request_user_input. Testable verification criteria. | category-1 direction-setting |
|
|
59
|
+
| **consulted** / **informed** (frontmatter) | Default to empty list per Step 4 template; fold into the decision-makers request_user_input call if the user surfaces stakeholders. | category-4 silent-framework (default empty); category-1 (when user cites stakeholders) |
|
|
49
60
|
|
|
50
61
|
**Inferred fields (no ask, no advisory needed)**:
|
|
51
62
|
|
|
52
63
|
- **supersedes** (frontmatter): empty list by default; populated only via Step 6 supersession handling when the user explicitly cites a superseded decision.
|
|
53
64
|
|
|
54
|
-
**Stderr advisory contract**: each derived field emits a SINGLE line to stderr (NOT stdout, NOT in the ADR body) via the shared helper's `emit_stderr_advisory` function in
|
|
65
|
+
**Stderr advisory contract**: each derived field emits a SINGLE line to stderr (NOT stdout, NOT in the ADR body) via the shared helper's `emit_stderr_advisory` function in `<architect-plugin-root>/lib/derive-first-dispatch.sh`. The canonical format produced by the helper:
|
|
55
66
|
|
|
56
67
|
```
|
|
57
68
|
create-adr: derived <field>=<value> from <source>; <reversibility-clause>
|
|
@@ -61,11 +72,11 @@ The advisory text shape is I2-isomorphic — same sentence structure across all
|
|
|
61
72
|
|
|
62
73
|
**ADR-026 cost-source grounding**: each derived field cites its source in the advisory (problem-statement token sequence for Title; today's date for date / reassessment-date; default convention for status). The `re-invoke or update if mis-rated` clause carries the reversibility marker ADR-026 mandates for ungrounded outputs.
|
|
63
74
|
|
|
64
|
-
**AFK fail-safe (ADR-013 Rule 6)**: under AFK orchestration, derivable fields (Title / status / date / reassessment-date / Context-when-prose-present) resolve without interactive input. The 6 retained cat-1
|
|
75
|
+
**AFK fail-safe (ADR-013 Rule 6)**: under AFK orchestration, derivable fields (Title / status / date / reassessment-date / Context-when-prose-present) resolve without interactive input. The 6 retained cat-1 request_user_input surfaces (decision-makers / Decision Drivers / Considered Options / Decision Outcome / Consequences / Confirmation) WILL halt AFK execution — that is **correct behaviour** because ADR creation is genuinely user-judgment-bound (the user authors the decision; the framework cannot). JTBD-006 protection: AFK orchestrators that need ADR creation should call `/wr-architect:capture-adr` (the lightweight aside surface), which derives ALL section content silently at capture (ADR-032 derived-substance amendment, RFC-045) and records it `human-oversight: unconfirmed`; the user ratifies or amends the derived substance at the next interactive `/wr-architect:review-decisions` drain (surfaced by the self-firing SessionStart oversight nudge). The cat-1 classification above governs THIS interactive intake surface — on the capture surface the same fields are derived-provisional-then-ratified, not asked (the ADR-067 pattern); the two surfaces do not conflict.
|
|
65
76
|
|
|
66
77
|
**Cross-skill consistency note**: this is the **fourth declaration-skill surface** to ship the derive-first dispatch (after `/wr-itil:capture-problem` Step 1.5, `/wr-itil:manage-incident` Step 4, and `/wr-itil:manage-problem` Step 4 in commits b7cc645 / 43255d2 / 30fd22b). Phase 2a-iii-B (2026-05-16) closes Phase 2a's full 4-surface scope — the I2-isomorphic stderr advisory format is now locked-in across `capture-problem`, `manage-incident`, `manage-problem`, AND `create-adr` via the shared helper at `packages/shared/derive-first-dispatch.sh` with synced per-package lib/ copies. Per ADR-017, drift between copies is caught by `npm run check:derive-first-dispatch` in CI.
|
|
67
78
|
|
|
68
|
-
If the user has already provided context in `$ARGUMENTS` or earlier conversation, use what they've given and only fire
|
|
79
|
+
If the user has already provided context in `$ARGUMENTS` or earlier conversation, use what they've given and only fire request_user_input for the cat-1 fields still missing.
|
|
69
80
|
|
|
70
81
|
### 2a. Title-as-outcome convention (P354)
|
|
71
82
|
|
|
@@ -100,14 +111,14 @@ Before writing the ADR file, perform a decision-boundary analysis on the gathere
|
|
|
100
111
|
- **Single decision** (one coherent question with one chosen option): proceed directly to step 3.
|
|
101
112
|
- **Multiple decisions** (two or more distinct questions, different components, or different decision drivers that do not share the same trade-off): present a split prompt.
|
|
102
113
|
|
|
103
|
-
**Split prompt** — use `
|
|
114
|
+
**Split prompt** — use `request_user_input`:
|
|
104
115
|
- `header: "Multi-decision input"`
|
|
105
116
|
- `multiSelect: false`
|
|
106
117
|
- Options:
|
|
107
118
|
1. `Split into separate ADRs (Recommended)` — description: "Create one ADR per distinct decision, with consecutive IDs. Each ADR can be accepted, rejected, or superseded independently."
|
|
108
119
|
2. `Keep as a single ADR` — description: "Create one ADR covering all decisions. Use this only if the decisions are so tightly coupled that they cannot be made independently."
|
|
109
120
|
|
|
110
|
-
**Non-interactive fallback**: When `
|
|
121
|
+
**Non-interactive fallback**: When `request_user_input` is unavailable (e.g., non-interactive/AFK mode), automatically split into separate ADRs with consecutive IDs and note the auto-split in output. Do not block creation.
|
|
111
122
|
|
|
112
123
|
**ADR-013 Rule 6 carve-out audit (P352, 2026-06-06 amendment)**: the universal AFK default is **queue-and-continue**; this site is a documented **AUTO-DEFAULT** carve-out. Authorising principle: policy-authorised safe default per ADR-044 category 4 (silent framework). Splitting is fully reversible (manual combine via supersession), the framework's WSJF / lifecycle model rewards explicit per-decision ranking, and "split when in doubt" is the persona-correct safe heuristic for JTBD-006 (the loop progresses; over-splits are cheap to combine; halt would cost more loop throughput than the over-split risk). Note: the Step 5 substance-confirm HALT below is a separate carve-out authorised by ADR-074 — substance-confirm cannot AUTO-DEFAULT because the dependent work (Decision Outcome / Consequences / Confirmation / Pros and Cons drafting) is built ON the chosen option.
|
|
113
124
|
|
|
@@ -216,28 +227,28 @@ Use today's date for the `date` field. Set `reassessment-date` to 3 months from
|
|
|
216
227
|
|
|
217
228
|
### 5. Confirm with the user — two separate fires (P339 + P340)
|
|
218
229
|
|
|
219
|
-
Step 5 fires TWO separate `
|
|
230
|
+
Step 5 fires TWO separate `request_user_input` passes, in this order:
|
|
220
231
|
|
|
221
232
|
1. **Substance-confirm fire** — the user picks the chosen option from the considered-options set. THIS fire gates the born-confirmed marker write.
|
|
222
233
|
2. **Draft-quality review fire** (optional, after substance-confirm passes) — narrow questions on prose quality, consulted/informed list, edge cases. Does NOT gate the marker.
|
|
223
234
|
|
|
224
|
-
This split closes the P339 / P340 gap: previously Step 5 fired ONE bundled "review pass"
|
|
235
|
+
This split closes the P339 / P340 gap: previously Step 5 fired ONE bundled "review pass" request_user_input ("does the problem statement + Decision Outcome (Option X) capture the situation? — yes/no/edits/different-option"), and the user's "Yes" was treated as substance-ratification when in practice the user was confirming draft quality alone. The bundled answer landed the human-oversight marker on substance the user never explicitly affirmed. ADR-078 commit 5196e3d is the in-session exemplar; user correction 2026-05-31: *"I never approved the scripted extraction. You are supposed to run decisions by me"* + *"the previous iteration of the decision, with the programmatic extraction was not approved. How did that ADR skip ratification?"*. ADR-074 § Enforcement surface 1 is what this step now operationalises at the create-adr surface.
|
|
225
236
|
|
|
226
237
|
#### 5a. Substance-confirm fire (P340 — load-bearing for the marker write)
|
|
227
238
|
|
|
228
239
|
The substance-confirm fire MUST satisfy ALL FIVE interaction-pattern requirements pinned by user direction 2026-05-31 (encoded in ADR-064 + ADR-066 amendments + P340 § Root Cause Analysis):
|
|
229
240
|
|
|
230
|
-
1. **Briefing in main-turn prose** — emit the considered-options + selected-option + rationale as plain main-turn text BEFORE the `
|
|
241
|
+
1. **Briefing in main-turn prose** — emit the considered-options + selected-option + rationale as plain main-turn text BEFORE the `request_user_input` fires. The briefing carries the substance-of-the-decision in a form the user can read and reason about. Long request_user_input text is NOT readable on some devices (mobile clients, accessibility tooling, certain notification surfaces); long prose + short question IS readable across the full device matrix. The split is load-bearing — briefing carries the briefing; the request_user_input stays narrow.
|
|
231
242
|
|
|
232
|
-
2. **
|
|
243
|
+
2. **request_user_input is option-shaped, NOT yes/no** — the `options:` array MUST contain each considered option as a selectable option (one entry per considered option). The user picks the substantive direction positively (chooses ONE option), not by clicking "yes" on a bundled "is this OK?" question. Yes/no shape is forbidden at this fire.
|
|
233
244
|
|
|
234
|
-
3. **No IDs as explainers** — neither the briefing prose nor the `
|
|
245
|
+
3. **No IDs as explainers** — neither the briefing prose nor the `request_user_input` text/options/descriptions may use IDs (`ADR-NNN`, `P-NNN`, `JTBD-NNN`, `RFC-NNN`) as the carrier of meaning. The user does NOT have access to those IDs on all devices (mobile clients without the project filesystem; notification surfaces; accessibility readers that can't follow links). Every option's substance MUST be self-contained in the briefing prose + the option label/description. IDs may appear ONLY as audit-trail annotations after a self-contained explanation, never as the explanation itself.
|
|
235
246
|
|
|
236
|
-
4. **Informed-decision-without-external-document-lookup** — the briefing + question + options is a self-contained surface. If understanding a chosen option requires the user to first read another document, the briefing has failed. The briefing carries enough context that a user reading ONLY the main-turn text and the
|
|
247
|
+
4. **Informed-decision-without-external-document-lookup** — the briefing + question + options is a self-contained surface. If understanding a chosen option requires the user to first read another document, the briefing has failed. The briefing carries enough context that a user reading ONLY the main-turn text and the request_user_input can pick.
|
|
237
248
|
|
|
238
249
|
5. **Each option's substance is the actual chosen option** — the options array contains the actual considered options from the ADR draft (Option A / Option B / Option C / ... as worded in the Considered Options section), NOT meta-options ("yes accept draft" / "ask differently"). The label is a short readable phrase; the description carries the trade-off. Picking an option IS the substantive choice.
|
|
239
250
|
|
|
240
|
-
**Suggested
|
|
251
|
+
**Suggested request_user_input shape** (each considered option as one selectable option):
|
|
241
252
|
|
|
242
253
|
```text
|
|
243
254
|
question: "Which option should this ADR record as the chosen direction?"
|
|
@@ -254,7 +265,7 @@ options:
|
|
|
254
265
|
**Born-confirmed marker write (ADR-066 — tightened by P340 amendment + structurally gated by P348 amendment 2026-06-02).** The marker write fires ONLY when the substance-confirm answer specifies a substantive option from the considered-options set AND that option matches the option the draft was authored against. On a substantive match, IMMEDIATELY call the marker-evidence helper THEN insert the two lines:
|
|
255
266
|
|
|
256
267
|
```bash
|
|
257
|
-
|
|
268
|
+
bash "<architect-plugin-root>/scripts/mark-oversight-confirmed.sh" docs/decisions/<NNN>-<slug>.proposed.md
|
|
258
269
|
```
|
|
259
270
|
|
|
260
271
|
```yaml
|
|
@@ -262,7 +273,7 @@ human-oversight: confirmed
|
|
|
262
273
|
oversight-date: YYYY-MM-DD # today
|
|
263
274
|
```
|
|
264
275
|
|
|
265
|
-
The `
|
|
276
|
+
The `bash "<architect-plugin-root>/scripts/mark-oversight-confirmed.sh"` call writes the session-scoped evidence marker (`/tmp/oversight-confirmed-<sha>-<sid>`) that the `architect-oversight-marker-discipline.sh` PreToolUse hook reads to authorise the subsequent Edit/Write — without the helper call, the hook will DENY the marker write. AFK iter subprocesses spawned via `claude -p` have no `request_user_input` access; they MUST write `human-oversight: unconfirmed` instead (the AFK fallback enum value codified in ADR-066 amendment 2026-06-02), which the drain (`/wr-architect:review-decisions`) later promotes interactively. Calling the helper without a real user substance-confirm event is the P348 hollow-marker bug — every legitimate marker write traces back to an `request_user_input` answer in the same turn.
|
|
266
277
|
|
|
267
278
|
**ADR-013 Rule 6 carve-out audit (P352, 2026-06-06 amendment)**: the universal AFK default is queue-and-continue. This Step 5 substance-confirm HALT-and-write-`human-oversight: unconfirmed` shape is a documented carve-out, authorised by **ADR-074** (Confirm decision substance before building dependent work). Rationale: an ADR with `human-oversight: confirmed` enters the world born-confirmed (it does not appear in `/wr-architect:review-decisions`' unoversighted set), so dependent work — every implementation that cites this ADR as authority — would be built on substance that was never user-affirmed. AFK writing `human-oversight: unconfirmed` IS the queue-and-continue shape: the loop continues; the substance-confirm decision is queued to the next interactive drain. Persona-correct for JTBD-006 ("queued for my return, not guessed at"); the carve-out is from the auto-confirm shape, not from queue-and-continue itself.
|
|
268
279
|
|
|
@@ -270,7 +281,7 @@ The `wr-architect-mark-oversight-confirmed` call writes the session-scoped evide
|
|
|
270
281
|
|
|
271
282
|
- DO NOT write the marker.
|
|
272
283
|
- Re-draft Decision Outcome + Consequences + Confirmation + Pros and Cons (and Reassessment Criteria if affected) against the newly-chosen option.
|
|
273
|
-
- Re-fire the substance-confirm `
|
|
284
|
+
- Re-fire the substance-confirm `request_user_input` against the re-drafted text to verify the substance now matches the user's pick.
|
|
274
285
|
- The marker writes ONLY after a substance-confirm pass whose answer matches the draft on disk.
|
|
275
286
|
|
|
276
287
|
This is NOT a soft "warn and proceed" path — the marker only ever writes when the draft on disk encodes the user's substantive pick. Mismatch is a re-draft trigger, not an override.
|
|
@@ -279,7 +290,7 @@ This is NOT a soft "warn and proceed" path — the marker only ever writes when
|
|
|
279
290
|
|
|
280
291
|
**Retitle-after-decision check (P354 — ADR-044 category-4 silent-framework).** After the marker write lands, check the on-disk filename slug for a question-shape pattern (`-vs-`, `should-`, `whether-`, `-or-`). If matched, the title was derived at intake against a question-shaped problem-statement and must be retitled to the chosen-option's outcome shape now that the substance is locked in. The convention is named in Step 2a above.
|
|
281
292
|
|
|
282
|
-
This step is **mechanical — no
|
|
293
|
+
This step is **mechanical — no request_user_input fires** (per P132 inverse-P078 guard). The chosen option is now known from the substance-confirm answer just above; derive the outcome slug from the chosen-option short name via the same `derive_kebab_slug` helper Step 2's Title derivation uses (`<architect-plugin-root>/lib/derive-first-dispatch.sh`). Sequence (ordered to preserve marker-discipline hook semantics — the marker-introducing Edit must land BEFORE `git mv`):
|
|
283
294
|
|
|
284
295
|
1. Derive `new_slug = derive_kebab_slug "<chosen option short name>"`.
|
|
285
296
|
2. Edit the H1 in the on-disk file to the new outcome shape (H1 stays human-readable Title Case; the slug is for the filename). The `human-oversight: confirmed` line is already in `OLD_CONTENT` so `architect-oversight-marker-discipline.sh` allows this Edit per its "old content already had the marker" branch.
|
|
@@ -293,7 +304,7 @@ If the on-disk slug does NOT match a question-shape pattern (already outcome-sha
|
|
|
293
304
|
|
|
294
305
|
#### 5b. Draft-quality review fire (optional, after 5a passes)
|
|
295
306
|
|
|
296
|
-
After the substance-confirm fire passes and the marker is written, fire a separate narrow `
|
|
307
|
+
After the substance-confirm fire passes and the marker is written, fire a separate narrow `request_user_input` for draft-quality review:
|
|
297
308
|
|
|
298
309
|
1. Does the problem statement accurately capture the situation?
|
|
299
310
|
2. Are the pros/cons fair and complete?
|
|
@@ -305,7 +316,7 @@ Apply any feedback by editing the file. This fire is OPTIONAL — when the agent
|
|
|
305
316
|
**Refresh the decisions compendium (ADR-077).** After the ADR file is written and any born-confirmed marker is applied, regenerate `docs/decisions/README.md` so the architect-agent routine load surface includes the new entry. Run:
|
|
306
317
|
|
|
307
318
|
```bash
|
|
308
|
-
|
|
319
|
+
bash "<architect-plugin-root>/scripts/generate-decisions-compendium.sh"
|
|
309
320
|
git add docs/decisions/README.md
|
|
310
321
|
```
|
|
311
322
|
|
|
@@ -14,10 +14,12 @@ setup() {
|
|
|
14
14
|
[ "$status" -eq 0 ]
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
@test "create-adr Codex eval runner uses
|
|
18
|
-
run grep -n
|
|
17
|
+
@test "create-adr Codex eval runner uses packed installer and codex exec" {
|
|
18
|
+
run grep -n 'npm pack' "$EVAL_DIR/run-codex-skill-eval.sh"
|
|
19
19
|
[ "$status" -eq 0 ]
|
|
20
|
-
run grep -n
|
|
20
|
+
run grep -n 'windyroad-architect --runtime codex --scope user' "$EVAL_DIR/run-codex-skill-eval.sh"
|
|
21
|
+
[ "$status" -eq 0 ]
|
|
22
|
+
run grep -n 'agents/wr-architect-agent.toml' "$EVAL_DIR/run-codex-skill-eval.sh"
|
|
21
23
|
[ "$status" -eq 0 ]
|
|
22
24
|
run grep -n "codex exec" "$EVAL_DIR/run-codex-skill-eval.sh"
|
|
23
25
|
[ "$status" -eq 0 ]
|
|
@@ -27,4 +29,6 @@ setup() {
|
|
|
27
29
|
[ "$status" -eq 0 ]
|
|
28
30
|
run grep -n -- "--sandbox read-only" "$EVAL_DIR/run-codex-skill-eval.sh"
|
|
29
31
|
[ "$status" -eq 0 ]
|
|
32
|
+
run grep -n -- '</dev/null' "$EVAL_DIR/run-codex-skill-eval.sh"
|
|
33
|
+
[ "$status" -eq 0 ]
|
|
30
34
|
}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wr-architect:review-decisions
|
|
3
|
-
description: Drain the set of recorded decisions (ADRs) that lack human oversight. Surfaces each unconfirmed ADR's chosen option and alternatives via
|
|
4
|
-
allowed-tools: Read, Glob, Grep, Bash, Edit,
|
|
3
|
+
description: Drain the set of recorded decisions (ADRs) that lack human oversight. Surfaces each unconfirmed ADR's chosen option and alternatives via request_user_input so a human confirms, amends, or rejects the auto-made call, then writes the human-oversight marker. Use when the session-start nudge reports decisions lack oversight, or any time you want to review recorded decisions.
|
|
4
|
+
allowed-tools: Read, Glob, Grep, Bash, Edit, request_user_input
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
<!-- Generated from the Claude skill source during npm pack. -->
|
|
8
|
+
|
|
9
|
+
> Codex runtime note: use `request_user_input` in Plan Mode for structured
|
|
10
|
+
> questions. Resolve `<architect-plugin-root>` from this installed
|
|
11
|
+
> `SKILL.md` path: it is two directories above the skill directory. Replace
|
|
12
|
+
> that token with the absolute path before running a bundled script; never
|
|
13
|
+
> search the adopter repository or rely on a `wr-architect-*` command being
|
|
14
|
+
> on `PATH`. Spawn the installed `wr-architect:agent` custom agent with the
|
|
15
|
+
> native Codex subagent tool, wait for it, and close the same agent.
|
|
16
|
+
|
|
17
|
+
|
|
7
18
|
# Review Decisions — human-oversight drain
|
|
8
19
|
|
|
9
|
-
Lift auto-made architecture decisions to human decisions. Many ADRs were recorded autocratically — the architect proposed an option and it stood without a human picking it. This skill drains the **unoversighted set** (ADRs lacking `human-oversight: confirmed` in frontmatter, per ADR-066): it surfaces each decision's chosen option + the alternatives via `
|
|
20
|
+
Lift auto-made architecture decisions to human decisions. Many ADRs were recorded autocratically — the architect proposed an option and it stood without a human picking it. This skill drains the **unoversighted set** (ADRs lacking `human-oversight: confirmed` in frontmatter, per ADR-066): it surfaces each decision's chosen option + the alternatives via `request_user_input`, and writes the oversight marker only when a human confirms.
|
|
10
21
|
|
|
11
|
-
This is the P283 prong-2 drain surface. It is the eat-our-own-dogfood loop: confirming a decision is itself a human decision, so it goes through `
|
|
22
|
+
This is the P283 prong-2 drain surface. It is the eat-our-own-dogfood loop: confirming a decision is itself a human decision, so it goes through `request_user_input`.
|
|
12
23
|
|
|
13
24
|
## When to use
|
|
14
25
|
|
|
@@ -26,18 +37,18 @@ Each run drains as many ADRs as the user has appetite for, in topic-clustered ba
|
|
|
26
37
|
Run the detector (token-cheap — grep over frontmatter, no body reads):
|
|
27
38
|
|
|
28
39
|
```bash
|
|
29
|
-
|
|
40
|
+
bash "<architect-plugin-root>/scripts/detect-unoversighted.sh" docs/decisions
|
|
30
41
|
```
|
|
31
42
|
|
|
32
|
-
The `
|
|
43
|
+
The `bash "<architect-plugin-root>/scripts/detect-unoversighted.sh"` command is the bundled Codex script at `<architect-plugin-root>/scripts/detect-unoversighted.sh`. It prints one unoversighted ADR path per line (superseded ADRs are excluded — a retired decision needs no confirmation). Empty output → the set is fully drained; report "all recorded decisions carry human oversight" and stop.
|
|
33
44
|
|
|
34
45
|
### Step 2: Cluster + order
|
|
35
46
|
|
|
36
47
|
Read **only the frontmatter + title + Decision Outcome** of each unoversighted ADR (not full bodies — keep it cheap). Group by topic cluster (e.g. release-cadence, governance-gates, AFK-orchestration, decision-recording) and order **load-bearing first**: ADRs that other ADRs cite as parents, that are `accepted` (already shipped — highest drift cost if the auto-pick was wrong), or that govern a hook/gate the user interacts with daily. Defer narrow / low-coupling ADRs.
|
|
37
48
|
|
|
38
|
-
### Step 3: Present each decision via
|
|
49
|
+
### Step 3: Present each decision via request_user_input (batched)
|
|
39
50
|
|
|
40
|
-
For each ADR in the ordered queue, surface the decision as an `
|
|
51
|
+
For each ADR in the ordered queue, surface the decision as an `request_user_input` (cap **4 ADRs per call** per ADR-013 Rule 1; issue further calls sequentially). For each ADR:
|
|
41
52
|
|
|
42
53
|
- **Question**: the decision the ADR records (its Decision Outcome, in one line).
|
|
43
54
|
- **Context**: the chosen option + the alternatives the ADR considered (grounded in the ADR's Considered Options section per ADR-026), and any cited parent ADRs.
|
|
@@ -47,7 +58,7 @@ For each ADR in the ordered queue, surface the decision as an `AskUserQuestion`
|
|
|
47
58
|
- **Reject / supersede** — the auto-made pick is wrong; capture the supersede ticket (see Step 4) and write the **rejected-pending-supersede** marker so the drain stops re-asking.
|
|
48
59
|
- **Defer** — skip this sitting; leave unoversighted for a later run.
|
|
49
60
|
|
|
50
|
-
**Presentation rule — lead with the Decision Outcome, never with the meta (P302).** The
|
|
61
|
+
**Presentation rule — lead with the Decision Outcome, never with the meta (P302).** The request_user_input `question` field MUST open with the one-line Decision Outcome — *what the ADR decides* — phrased as `"This ADR decides: <outcome>"`. Sibling-ADR relationships, supersession lineage, and Considered-Options recording-shape (e.g. "separate ADR vs amend ADR-014") are **meta** about *how the decision was recorded*, not what it decides — relegate them to a trailing clause or omit. This is ADR-074's *name the substance, not the grain* principle applied to the confirm surface itself, and ADR-026 grounding extended from the ADR body to the request_user_input `question` text. Burying the substance behind meta forces a clarifying re-ask: the user cannot tell what they are confirming.
|
|
51
62
|
|
|
52
63
|
*Bad — buries the decision behind meta:*
|
|
53
64
|
- *"a sibling ADR codifying five patterns; ADR-038 governs UserPromptSubmit, ADR-040 governs SessionStart."* (ADR-045 surfaced this way during the 2026-05-25 drain; user replied *"if this decision defers to a sibling decision, what does this decision decide??"*.)
|
|
@@ -61,13 +72,13 @@ The trailing clause exists for cross-reference value — it is optional, NOT a r
|
|
|
61
72
|
|
|
62
73
|
**Brief-before-ID discipline (P350).** The `question` and `options` text MUST inline what each referenced artefact is and what is at stake before naming it by ID. `ADR-NNN` / `P-NNN` / `JTBD-NNN` / `RFC-NNN` references are audit-trail annotations, NEVER carriers of meaning — the user reads this prompt without project filesystem access (mobile clients, accessibility tooling, notification surfaces) and cannot follow links. Acceptable: *"This ADR decides: five per-tool-call hook patterns + their budget bands (sibling of the UserPromptSubmit-pattern decision and the SessionStart-pattern decision)."* Unacceptable: *"This ADR decides: 5 patterns; sibling to ADR-038 and ADR-040."* The trailing parenthetical IDs are permitted ONLY after a self-contained explanation, never as the explanation itself. Mirrors the canonical `/wr-architect:create-adr` Step 5 § 5a Rule 3 ("No IDs as explainers"). See also session memory `feedback_brief_before_id.md`.
|
|
63
74
|
|
|
64
|
-
This is a genuine human-decision surface (the whole point of P283) — `
|
|
75
|
+
This is a genuine human-decision surface (the whole point of P283) — `request_user_input` is correct here and is NOT over-asking. Do not auto-confirm; do not prose-ask.
|
|
65
76
|
|
|
66
77
|
### Step 4: Apply the outcome
|
|
67
78
|
|
|
68
79
|
- **Confirm / Amend**: write `human-oversight: confirmed` + `oversight-date: <today, YYYY-MM-DD>` into the ADR's frontmatter (insert after the `date:` line if absent; never duplicate). For Amend, apply the directed body change first. Both edits go through the standard architect / JTBD edit gate per ADR-014.
|
|
69
80
|
- **Reject / supersede** (ADR-066 amendment per P316):
|
|
70
|
-
1. Capture the supersede ticket via a follow-up `
|
|
81
|
+
1. Capture the supersede ticket via a follow-up `request_user_input`: "Which problem ticket tracks the supersede?" — options: existing `P<NNN>` IDs surfaced from `docs/problems/`, **Capture a new ticket** (delegate to `/wr-itil:capture-problem`), or **Defer (leave un-tracked for now)**.
|
|
71
82
|
2. If a ticket ID is captured, write `human-oversight: rejected-pending-supersede` + `supersede-ticket: P<NNN>` into the ADR's frontmatter. The detector excludes ADRs carrying both, so the drain stops re-asking until either the supersede ADR lands (status flips to `superseded`) or the rejection is revisited.
|
|
72
83
|
3. If the user defers ticket capture, leave the marker absent — the ADR re-surfaces next drain (the un-tracked case is intentionally re-asked so it doesn't silently rot).
|
|
73
84
|
- **Defer**: no write.
|
|
@@ -77,7 +88,7 @@ This is a genuine human-decision surface (the whole point of P283) — `AskUserQ
|
|
|
77
88
|
After the batch's Confirm/Amend/Reject writes land in the working tree, regenerate `docs/decisions/README.md` so the architect-agent routine load surface reflects the new substance and badges:
|
|
78
89
|
|
|
79
90
|
```bash
|
|
80
|
-
|
|
91
|
+
bash "<architect-plugin-root>/scripts/generate-decisions-compendium.sh"
|
|
81
92
|
```
|
|
82
93
|
|
|
83
94
|
The compendium is the architect agent's primary load surface per ADR-077; review-decisions owns keeping it fresh through this drain (skills + agent are PRIMARY; the `architect-compendium-refresh-discipline.sh` hook is the safety-net backstop). Why this matters per disposition:
|
|
@@ -108,7 +119,7 @@ Commit the drained batch per ADR-014 (one commit for the sitting's drained batch
|
|
|
108
119
|
## Related
|
|
109
120
|
|
|
110
121
|
- **ADR-066** — the oversight marker + this drain skill + the detector + the nudge.
|
|
111
|
-
- **ADR-064** — the architect Needs-Direction verdict; the main agent owns `
|
|
122
|
+
- **ADR-064** — the architect Needs-Direction verdict; the main agent owns `request_user_input` (this skill is that ownership applied to the existing set).
|
|
112
123
|
- **ADR-009** — never-re-ask persistent-marker principle (the marker, not its TTL/drift lifecycle).
|
|
113
124
|
- **ADR-013 / ADR-044** — structured user interaction + decision-delegation taxonomy.
|
|
114
125
|
- **ADR-077** — generated decisions compendium as the architect agent's routine load surface; Step 4.5 + Step 5 keep it fresh through this drain (Confirmation item (f)). Mirrors the same regen + stage-with-commit pattern used by `/wr-architect:create-adr` Step 5 and `/wr-architect:capture-adr` Step 4.5.
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: wr-architect:review-design
|
|
3
3
|
description: On-demand architecture compliance review. Checks staged changes and recent commits against existing ADRs in docs/decisions/. Use before editing architecture-bearing files or before a release.
|
|
4
|
-
allowed-tools: Read, Glob, Grep, Bash,
|
|
4
|
+
allowed-tools: Read, Glob, Grep, Bash, request_user_input, Skill
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
<!-- Generated from the Claude skill source during npm pack. -->
|
|
8
|
+
|
|
9
|
+
> Codex runtime note: use `request_user_input` in Plan Mode for structured
|
|
10
|
+
> questions. Resolve `<architect-plugin-root>` from this installed
|
|
11
|
+
> `SKILL.md` path: it is two directories above the skill directory. Replace
|
|
12
|
+
> that token with the absolute path before running a bundled script; never
|
|
13
|
+
> search the adopter repository or rely on a `wr-architect-*` command being
|
|
14
|
+
> on `PATH`. Spawn the installed `wr-architect:agent` custom agent with the
|
|
15
|
+
> native Codex subagent tool, wait for it, and close the same agent.
|
|
16
|
+
|
|
17
|
+
|
|
7
18
|
# Architecture Compliance Review Skill
|
|
8
19
|
|
|
9
20
|
Run an architecture compliance review on demand — outside the pre-tool-use hook gate. Reviews staged changes and recent commits against the project's ADRs in `docs/decisions/`.
|
|
@@ -49,7 +60,7 @@ Summarise:
|
|
|
49
60
|
|
|
50
61
|
### 3. Resolve ambiguity
|
|
51
62
|
|
|
52
|
-
If there are no staged changes and no recent unpushed commits, use `
|
|
63
|
+
If there are no staged changes and no recent unpushed commits, use `request_user_input` to ask:
|
|
53
64
|
|
|
54
65
|
> "I don't see any staged or unpushed changes. What would you like me to review?
|
|
55
66
|
> (a) A specific set of files — please name them
|
|
@@ -87,7 +98,7 @@ agent: wr-architect:agent
|
|
|
87
98
|
prompt: <constructed review prompt from step 4>
|
|
88
99
|
```
|
|
89
100
|
|
|
90
|
-
Codex
|
|
101
|
+
The Codex installer generates `.codex/agents/wr-architect-agent.toml` from the installed plugin's `agents/agent.md` and registers the exact identity `wr-architect:agent`. SessionStart repairs the user-scoped registration when needed. Adopter projects do not need to ship their own agent configuration. Restart Codex if that exact identity is not visible; do not substitute the built-in `default` agent because the review marker consumes the architect identity. The repo-local `.codex/agents/wr-architect.toml`, kept in sync from `<architect-plugin-root>/agents/agent.md` by `scripts/sync-codex-agents.mjs`, remains the short-name `wr-architect` alias for source-repo dogfooding.
|
|
91
102
|
|
|
92
103
|
Wait for the agent to complete.
|
|
93
104
|
|