Files
ai-agent/PROJECT_CLAUDE.md
Gabriel Vidal 74393fa474 feat(hub): deliver a follow-up into a live run through its inbox
_send_message now POSTs the prompt to the sidecar's /message first: a
run that is still alive keeps its background work (a build, a subagent,
a Monitor on a form) and reads the message between tool calls, or at
once when idle. Only 404 (nothing live) or 409 (the run can't take it —
a pi run, an older CLI) falls back to the old stop-then-resume.

Claude Code records such a message as a peer's ("Another Claude session
sent a message … not typed by your user"); the sidecar prefixes the text
to say it is the user's, and conversations._unwrap_inbox shows the plain
user turn. SpawnResult gains `delivered: "inbox"`.

Docs: the headless background-task semantics in CLAUDE.md and
PROJECT_CLAUDE.md; FakeWorker learns /message for the routing tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 23:24:50 +02:00

126 lines
6.0 KiB
Markdown

# Project working conventions
Generic, host-agnostic conventions for working in a repo that the ai-agent tool
manages. These are the portable rules — worktree workflow, artefacts, plans,
committing, and how to signal a task is finished — with none of the homelab's
Traefik/Compose/registry specifics baked in. A concrete repo (e.g. the homelab)
keeps its own `CLAUDE.md` for its architecture and layers this on top; the
ai-agent ships this file as the starting point for a new project's root
`CLAUDE.md`.
Anything wrapped in `{{…}}` is a placeholder to fill in per repo.
## Before you edit: isolate your work
**Spin up an isolated git worktree and work there**, rather than editing files on
the checked-out branch. Before creating the worktree, pull the latest `main` so
the worktree starts from current state.
- `{{worktree_command}}` — create the worktree (e.g. `scripts/new-worktree.sh`).
- `{{pull_command}}` — pull `main` first (e.g. `git pull`, or an
auth-wrapped variant if a proxy fronts your git host).
Skip the worktree only for trivial, read-only inspection; any change to tracked
files goes through one.
## Directory conventions
- `data/` — file-backed working data: notes, logs, plans, boards. Not tracked in
git. Write a plan to `data/log/<YYYY-MM-DD>-[title].md`.
- **Generated artefacts** (images, screenshots, renders, charts, exports — any
binary/media file) tied to a project go into that project's artefact folder:
```
<projectFolder>/.ai/artefacts/<YYYY-MM-DD>/<sessionId>/<file>
```
where `<projectFolder>` is the **canonical** directory (never a worktree copy —
worktrees get deleted and aren't mounted into the viewer) and `<sessionId>` is
the current conversation id (`$CLAUDE_SESSION_ID`, else resolve it via the
session-id helper). The ai-agent viewer serves these folders: images you `Read`
from there render inline in the tool call, and the conversation details page
lists the whole set in its **Artefacts** card. Add `.ai/` to the repo's
`.gitignore` (or `.git/info/exclude`) if it isn't already ignored.
- Artefacts tied to no particular project still go under `data/` — e.g.
`data/artifacts/<YYYY-MM-DD>-[title].png` — which is likewise mounted into the
viewer and previewed inline. Files written anywhere else can't be served or
previewed.
## Waiting on background work in a spawned run
A spawned session is a headless `claude -p` run: **the process exits when you
end your turn**. Ending a turn with "I'll pick this up when it reports back" is
fine only because the runner guards it:
- a background **subagent** or **Monitor** is waited for up to the runner's
ceiling (2 h by default) — long enough for a build or a form answer;
- a plain **background shell** (`Bash run_in_background`) would die at once; a
Stop hook holds the turn until it has exited and then hands you its output
file. If you are told a task is still running after the hold, either
`TaskStop` it or end your turn again.
Prefer a Monitor for anything you wait on for more than a few minutes, and
never park work on a `sleep` loop. A follow-up message the user sends while
the run is alive arrives in the thread as a user turn — it does not restart
the session.
## Committing changes
**Commit after each change.** When you finish a logical unit of work — a source
edit, a config change, a script, docs — commit it right away in its own focused
commit rather than batching unrelated changes, and push as you go.
Use `{{commit_command}}` to commit and push (e.g. the `commit-project` skill for
per-project Gitea/GitHub repos, or a repo-specific commit skill).
## Finishing a feature: open a documented PR
When the task's guidelines ask for a PR instead of a deploy, finish feature
work by pushing the branch and opening a pull request with `{{pr_command}}`
(e.g. the `open-pr` skill), assigned to the repo owner. The PR body is the
feature's documentation — write it with these sections:
- **Summary** — what changed and why, for someone reading history later.
- **Key changes** — one bullet per meaningful change, not per commit.
- **Key decisions** — non-obvious choices and their trade-offs.
- **Changelog** — user-facing Keep-a-Changelog bullets (`Added/Changed/Fixed/
Removed`); these entries are harvested to generate the project's changelog.
- **Test notes** — how it was verified.
Attach a screenshot of any visible result. Deployment happens after the PR is
reviewed and merged, not as part of the task.
## When work is done
**Send a push notification after finishing any task the user kicked off** — not
just long-running ones but every completed task — so they know it's done:
```bash
{{notify_command}} "✅ Task finished" "short outcome" --type {{type}}
```
Keep it short: say what finished and the outcome. Pass `--type <type>` to pick a
fitting icon and `--url <url>` when the task has a more relevant page than the
default (the conversation in the ai-agent viewer).
**Then end the turn with `DONE`.** After sending that notification, your final
message must end with the literal marker `DONE` on its own line. The ai-agent
conversation viewer keys "finished" off this: a conversation that has both
recorded a notification and ended its last message with `DONE` is shown as
finished, instead of being stuck on the stale `running` badge the
worktree/select-project step set at the start.
## Completing the conversation
When the task guidelines ask you to **complete** the conversation, read
`.claude/skills/complete/SKILL.md` after that final notification and follow it.
It waits 30 s (a window for the user to redirect after reading the result), then
publishes the conversation's summary (`conv-scaffold` + one subagent) and tidies
up — memories, docs, artefacts, worktrees, changelog. That pass signs off with
`COMPLETED` instead of `DONE`, which is what puts the COMPLETED seal on the
conversation card.
It runs **in this session**, before it ends: resuming a finished conversation
re-creates its whole transcript as fresh input tokens, so the same work costs
several times more once the process has exited.