Files
2026-09-11 09:44:13 +02:00

182 lines
7.9 KiB
Markdown

---
name: project
description: >
Switch between named ongoing projects, each with its own persistent
context, carried forward across turns until the user switches or ends it.
Triggers on: "project X", "switch to project X", "we're working on X",
"list projects", "end project" / "no project". For a long-lived, named
work context — not a single task to plan and execute, and not a short or
global fact to remember.
---
# Project
Named, long-lived work contexts. Each project keeps its own instructions, its
own history, its own current-state summary, and its own generated files —
separate from every other project and from the agent's general memory.
## Layout
`workspace/projects/<slug>/`:
- `prompt.md`**what doesn't change**: purpose, goals, scope, constraints,
how the user wants to work on this. Read in full whenever the project
becomes active.
- `memory.md` — append-only chronological log of decisions and history
- `state.md`**what changes**: the living synthesis of where the project is
now. Progress, current approach, open questions, "what's next". Edited in
place, never appended to.
- `artifacts/` — generated files (documents, code, data exports, reports)
If you're about to write anything time-varying into `prompt.md` (a "current
status" or "next steps" section), put it in `state.md` instead.
**Which project is active is tracked purely through conversation memory —
nothing is persisted to disk for that.**
## Script
All project file operations go through one script, run from the workspace root:
`uv run skills/project/scripts/project_cli.py <subcommand>`
It owns the entry date and the append hygiene so they can't be guessed wrong.
## Activation
Triggered by "project X" / "switch to project X" / "we're working on X":
1. Turn `X` into a kebab-case directory name (like picking a slug for a plan
file — no need to spell out an algorithm, just pick something sensible).
2. Run `project_cli.py activate <slug>`. On success it prints `prompt.md`,
`memory.md` and `state.md` (creating any that are missing), so no separate
reads are needed. Then briefly confirm what's active and, if `prompt.md` or
`state.md` has content, what context you loaded.
3. **Exit 1 means no such project.** The error lists the existing ones. If one
is a close match (case-insensitive), ask which was meant — don't guess, and
don't create a near-duplicate.
4. **No close match** → ask the user whether to start a new project with that
name. Only on an explicit yes, run `project_cli.py new <slug>`. Never create
a project just because a trigger phrase was said.
**Already active:** if the same project is already active in this
conversation, don't re-run activation — just continue.
## Staying active
Once a project is active, keep applying its `prompt.md` instructions and
`state.md` context for the rest of the conversation, until the user switches
or ends it.
**If the file contents are no longer in your context** (a long conversation
gets compacted, and the loaded files can drop out of it while the memory that
a project is active stays), run `activate` again. Never answer from a faded
recollection of `prompt.md` or `state.md`.
If a long gap or an ambiguous reference makes it unclear whether the project
is still the right context (e.g. the conversation has clearly moved to an
unrelated topic), ask rather than silently carrying it forward or silently
dropping it.
## Switching and ending
- **"switch to Y"** → run the Activation flow for Y; Y becomes active
instead.
- **"end project" / "no project" / "stop working on X"** → stop treating any
project as active. Say so. Don't delete anything.
- With no active project, behave normally — never force a project onto an
unrelated request.
## Writing to memory.md
**Only ever through the script** — never `edit_file` or `write_file` on
`memory.md` itself. Two steps: write the entry text to a scratch file, then hand
the script its path.
1. `write_file` the entry text to `tmp/project-entry.md`
2. `uv run skills/project/scripts/project_cli.py log <slug> --file tmp/project-entry.md`
**Never put the entry text into the command line** — not as an argument, not in a
heredoc, not through a pipe. The exec safety guard scans the raw command string
and misreads ordinary prose as a filesystem path: a colon right after a letter
that follows a diacritic parses as a Windows drive, so Czech words like `Cíl:`,
`Závěr:` or `směr:` block the whole command with *path outside working dir*. The
guard has no shell parser, so quoting and heredocs do not help. A file path in
the command is unaffected.
The script prepends today's date and guarantees the entry starts on its own
line. Write the entry in the user's language, reformulated, not verbatim.
Write an entry when a decision is made, a dead end is found, or a fact central
to the project's ongoing context emerges — not for routine back-and-forth. When
in doubt, **write it**: losing something the user told you is worse than an
entry that turns out to be unremarkable. Entry length is not limited — capture
the reasoning behind a decision, not just its outcome.
**Correcting an entry:** `memory.md` is append-only, so never rewrite history.
Log a new entry starting with `correction:` that states what was wrong.
## Maintaining state.md
Edited in place with `edit_file`: surgically update the relevant section when
the project's current state or understanding has moved on enough that the old
text would mislead a reader. It answers "where is this now", not "what
happened" — old content gets replaced, not appended to.
**If `state.md` is empty and `memory.md` has content, draft it** from that
history and show the user the result. Don't just offer. Likewise, if
`prompt.md` still holds a time-varying section, move it here.
## Answering questions about a project
Answers that live in project files come **from the files**, not from memory:
read or `grep` them. If a project is active, its files are the first place to
look; with no project active, `grep` across `workspace/projects/` to find where
something was written.
## What goes where
While a project is active, a fact tied to that project goes into its
`memory.md` via the script. A durable fact about the user in general — one that
would still matter with no project active — goes to the normal memory path
instead.
## Artifacts
Files generated while working on the project (documents, code, data exports,
reports) go in `workspace/projects/<slug>/artifacts/`, created the first time
one is written. Name them descriptively; no numbering or index file needed at
this scale.
## Growth
`memory.md` grows without limit and is **never compacted, archived or
summarized**. When it gets long, `activate` simply stops printing all of it and
says where the rest is — read or `grep` the file directly for older context.
Never delete, shorten or rewrite stored content to save space.
## Listing
**"list projects" / "which projects exist":** run `project_cli.py list`. It
prints each project with its file sizes; `(!)` marks an empty `state.md`.
## Edge cases
- "project" with no name → ask which project.
- Missing `prompt.md` / `memory.md` / `state.md` (e.g. directory made by hand)
`activate` creates them, don't error.
- Deleting or renaming a project is out of scope for this skill — point the
user at `workspace/projects/<slug>/` to do it by hand.
## Rules
- This skill's body is English; reply to the user in their own language, and
write project files in the user's language too.
- Never fabricate project content — `prompt.md`, `memory.md`, and `state.md`
only grow from what the user actually said or what actually happened.
- Never write test or throwaway entries to a real project's `memory.md` — it is
append-only, so taking them back out means rewriting history. If you genuinely
need to try something, run `new <scratch-slug>` and use that.
- Never create a new project without the user's explicit confirmation.
- Don't force a project context onto an unrelated request.