Skip to content

Commit 664122d

Browse files
committed
AI: workspace 2 - toolkit
1 parent fc13fd5 commit 664122d

File tree

4 files changed

+67
-25
lines changed

4 files changed

+67
-25
lines changed

AGENTS.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,15 @@ repository tree. Use the helper recipes to inspect and control them:
3131
workspace (the environment is prepared with `direnv allow`).
3232
- `just agents::workspace-clean <workspace-id>` – forget the workspace and delete
3333
its cached directory once the work is integrated.
34+
- `just agents::workspace-sync-tools <workspace-id>` – refresh the copied automation
35+
bundle inside a workspace without re-running the workflow.
3436

3537
Workspaces are stored under `${AI_WORKSPACES_ROOT:-$XDG_CACHE_HOME/ai-workspaces}`
36-
using a repository-specific namespace. See `design-docs/jj-workspaces.md` for the
37-
full rationale and lifecycle details.
38+
using a repository-specific namespace. Each workspace contains a `.agent-tools/`
39+
directory with the current automation (`agents.just`, `scripts/`, `rules/`). The helper
40+
copies these files before every run so workflows see the latest tooling even when the
41+
target change is older. See `design-docs/jj-workspaces.md` for full rationale and
42+
lifecycle details.
3843

3944
# Code quality guidelines
4045

agents.just

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
workspace_id:=""
2+
13
consolidate workspace_id start_change_id end_change_id:
2-
scripts/agent-workspace.sh run {{workspace_id}} --workflow consolidate -- just --justfile .agent-tools/agents.just --set workspace_id={{workspace_id}} consolidate-inner {{start_change_id}} {{end_change_id}}
4+
bash scripts/agent-workspace.sh run {{workspace_id}} --workflow consolidate -- just --justfile .agent-tools/agents.just --set workspace_id {{workspace_id}} consolidate-inner {{start_change_id}} {{end_change_id}}
35

46
consolidate-inner start_change_id end_change_id:
57
#!/usr/bin/env sh
@@ -10,7 +12,7 @@ consolidate-inner start_change_id end_change_id:
1012

1113
Abide by the following rules:
1214

13-
`cat rules/spec.md`
15+
`cat "${AGENT_TOOL_COPY_ROOT:-.}/rules/spec.md"`
1416

1517
Here is a log of the changes in question:
1618

@@ -25,7 +27,7 @@ consolidate-inner start_change_id end_change_id:
2527

2628
jj new -r {{start_change_id}} -m "Consolidation in progress"
2729

28-
echo "$INSTRUCTIONS" | codex exec --full-auto --config model_reasoning_effort=high
30+
echo "$INSTRUCTIONS" | codex exec --skip-git-repo-check --full-auto --config model_reasoning_effort=high
2931

3032
workspace-status workspace_id='':
3133
@if [ -z "{{workspace_id}}" ]; then \
@@ -117,7 +119,7 @@ next-issue:
117119
3. Decide is it relevant to write a failing test for the issue. If so, write the test, make sure that it fails.
118120
Note! Not all issues require writing failing tests. Use discretion. Remember - code is debt.
119121
4. Change the code to fix the issue. Use "just dev test" to check if changes compile and tests pass.
120-
Code must follow the rules in '/rules/source-code.md'
122+
Code must follow the rules in '${AGENT_TOOL_COPY_ROOT:-.}/rules/source-code.md'
121123
5. When the issue is fixed and tests pass run "jj describe --stdin <<ENDDESC
122124
commit message
123125
ENDDESC".
@@ -131,7 +133,7 @@ next-issue:
131133

132134
Note! If you try to add a commit message like 'jj new -m "blah"' or 'jj describe -m "blah"' the resulting message will not be formatted properly.
133135

134-
`cat rules/writing.md`
136+
`cat "${AGENT_TOOL_COPY_ROOT:-.}/rules/writing.md"`
135137

136138
EOF
137139

@@ -161,9 +163,9 @@ review-change:
161163
...
162164
REVIEW'
163165

164-
`cat rules/writing.md`
166+
`cat "${AGENT_TOOL_COPY_ROOT:-.}/rules/writing.md"`
165167

166-
`cat rules/issues.md`
168+
`cat "${AGENT_TOOL_COPY_ROOT:-.}/rules/issues.md"`
167169
EOF
168170

169171
tidy-issues:
@@ -175,9 +177,9 @@ tidy-issues:
175177
4. Refactor the issues database to follow the specified rules. Do the MINIMAL changes necessary to make sure that the database follows the rules, while not removing any existing information in it.
176178
5. Finally update the file '/issues-overview.md' to match the changes in 'issues.md'. It is a table of issues and statuses.
177179

178-
`cat rules/writing.md`
180+
`cat "${AGENT_TOOL_COPY_ROOT:-.}/rules/writing.md"`
179181

180-
`cat rules/issues.md`
182+
`cat "${AGENT_TOOL_COPY_ROOT:-.}/rules/issues.md"`
181183
EOF
182184

183185
archive-issues:

design-docs/jj-workspaces.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ is trusted by `direnv` so the nix environment loads automatically.
1414
- Repository namespace: `${basename(repo)}-${sha256(repo-root)[0..10]}` to avoid
1515
collisions between repos with the same name.
1616
- Workspace path: `<root>/<repo-namespace>/<workspace-id>`.
17-
- Metadata file: `.agent-workflow.json` within every workspace, recording the workflow
18-
name, status, timestamps, and the command that is running.
17+
- Metadata file: `.agent-tools/.agent-workflow.json` within every workspace, recording the workflow
18+
name, status, timestamps, the command that is running, and the copied tooling hash.
1919

2020
Workspaces are never created under the repository itself. This keeps the main tree
2121
clean and prevents the permission issues we ran into when nesting workspaces inside
@@ -33,11 +33,25 @@ tracking directories.
3333
- `status`: Summarise all known workspaces or dump a single metadata file for inspection.
3434
- `shell`: Attach an interactive shell to an existing workspace (after running
3535
`direnv allow`). This is handy for manual interventions mid-workflow.
36+
- `sync-tools`: Refresh the copied tooling bundle inside a workspace.
3637
- `clean`: Remove the workspace after telling Jujutsu to forget it.
3738

39+
### Tool Copy Bundle
40+
41+
Each workspace receives a `.agent-tools/` directory containing the automation files
42+
needed for the workflows (currently `agents.just`, `scripts/`, and `rules/`). The helper
43+
copies these from the repository root (or from `AGENT_TOOLS_SOURCE`) before every run:
44+
45+
- The copy lives inside the workspace so the workflow sees consistent tooling even when
46+
the target change predates recent automation changes.
47+
- The directory is ignored via `.gitignore` so `jj status` stays clean.
48+
- `AGENT_TOOL_COPY_ROOT` points to the copy (defaults to `<workspace>/.agent-tools`).
49+
- `AGENT_TOOLS_VERSION` exposes the hash of the copied bundle. Metadata stores this
50+
together with `tools_source` and `tools_copy` for traceability.
51+
3852
Every command run inside a workspace receives environment variables describing where it
3953
is running: `AGENT_WORKSPACE_ID`, `AGENT_WORKSPACE_PATH`, `AGENT_WORKSPACE_METADATA`,
40-
`AGENT_WORKSPACE_REPO_ROOT`.
54+
`AGENT_WORKSPACE_REPO_ROOT`, `AGENT_TOOL_COPY_ROOT`, and `AGENT_TOOLS_VERSION`.
4155

4256
## Using the Workflows
4357

@@ -51,6 +65,8 @@ is running: `AGENT_WORKSPACE_ID`, `AGENT_WORKSPACE_PATH`, `AGENT_WORKSPACE_METAD
5165
rooted at the workspace.
5266
- `just agents::workspace-clean <workspace-id>` forgets the workspace in Jujutsu and
5367
removes the cached directory.
68+
- `just agents::workspace-sync-tools <workspace-id>` refreshes the copied tooling for a
69+
workspace without relaunching a workflow.
5470

5571
The helper does not auto-clean finished workspaces so that results can be inspected or
5672
rebased manually. Once the work is integrated, run the cleanup recipe to delete the

scripts/agent-workspace.sh

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ workspace_path_for() {
4949

5050
metadata_path_for() {
5151
local workspace_id="$1"
52-
echo "$(workspace_path_for "$workspace_id")/.agent-workflow.json"
52+
echo "$(workspace_path_for "$workspace_id")/.agent-tools/.agent-workflow.json"
53+
}
54+
55+
workspace_registered() {
56+
local workspace_id="$1"
57+
jj workspace list -T 'name ++ "\n"' | grep -Fx "$workspace_id" >/dev/null 2>&1
5358
}
5459

5560
compute_tools_hash() {
@@ -96,7 +101,8 @@ PY
96101
}
97102

98103
copy_tools_payload() {
99-
local dest="$1"
104+
local dest="$1"
105+
echo "*" > "$dest/.gitignore"
100106
python - "$tools_source_root" "$dest" "${tools_relative_paths[@]}" <<'PY'
101107
import shutil
102108
import sys
@@ -161,10 +167,23 @@ ensure_workspace() {
161167

162168
mkdir -p "$workspace_repo_root"
163169

164-
if jj workspace root --workspace "$workspace_id" >/dev/null 2>&1; then
165-
existing_path=$(jj workspace root --workspace "$workspace_id" | tr -d '\n')
166-
if [[ "$existing_path" != "$workspace_path" ]]; then
167-
fail "workspace '$workspace_id' already exists at '$existing_path'"
170+
if workspace_registered "$workspace_id"; then
171+
local metadata_path
172+
metadata_path=$(metadata_path_for "$workspace_id")
173+
if [[ -f "$metadata_path" ]]; then
174+
local recorded_path
175+
recorded_path=$(python - "$metadata_path" <<'PY'
176+
import json
177+
import sys
178+
path = sys.argv[1]
179+
with open(path, 'r', encoding='utf-8') as fh:
180+
data = json.load(fh)
181+
print(data.get('workspace_path', ''))
182+
PY
183+
)
184+
if [[ -n "$recorded_path" && "$recorded_path" != "$workspace_path" ]]; then
185+
fail "workspace '$workspace_id' already exists at '$recorded_path'"
186+
fi
168187
fi
169188
printf -v "$created_var" '%s' "false"
170189
else
@@ -307,7 +326,7 @@ run_subcommand() {
307326

308327
local workspace_path="$workspace_repo_root/$workspace_id"
309328
WORKSPACE_PATH="$workspace_path"
310-
local metadata_path="$workspace_path/.agent-workflow.json"
329+
local metadata_path="$workspace_path/.agent-tools/.agent-workflow.json"
311330
METADATA_PATH="$metadata_path"
312331

313332
local created_flag
@@ -419,7 +438,7 @@ rows = []
419438
for child in sorted(root.iterdir()):
420439
if not child.is_dir():
421440
continue
422-
meta_path = child / '.agent-workflow.json'
441+
meta_path = child / '.agent-tools' / '.agent-workflow.json'
423442
if not meta_path.exists():
424443
continue
425444
try:
@@ -456,7 +475,7 @@ shell_subcommand() {
456475
workspace_path=$(workspace_path_for "$workspace_id")
457476
[[ -d "$workspace_path" ]] || fail "workspace '$workspace_id' does not exist"
458477

459-
if ! jj workspace root --workspace "$workspace_id" >/dev/null 2>&1; then
478+
if ! workspace_registered "$workspace_id"; then
460479
fail "workspace '$workspace_id' is not registered with jj"
461480
fi
462481

@@ -483,7 +502,7 @@ clean_subcommand() {
483502
local workspace_path
484503
workspace_path=$(workspace_path_for "$workspace_id")
485504

486-
if jj workspace root --workspace "$workspace_id" >/dev/null 2>&1; then
505+
if workspace_registered "$workspace_id"; then
487506
jj workspace forget "$workspace_id"
488507
fi
489508

@@ -508,7 +527,7 @@ sync_tools_subcommand() {
508527

509528
[[ -d "$workspace_path" ]] || fail "workspace '$workspace_id' does not exist"
510529

511-
if ! jj workspace root --workspace "$workspace_id" >/dev/null 2>&1; then
530+
if ! workspace_registered "$workspace_id"; then
512531
fail "workspace '$workspace_id' is not registered with jj"
513532
fi
514533

0 commit comments

Comments
 (0)