Files
nanobot-runtime/skills/project/SKILL.md
2026-09-02 10:36:37 +02:00

7.1 KiB

name, description
name description
project 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.mdwhat 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.mdwhat 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. Pass the text on stdin with a quoted heredoc so quotes and apostrophes survive verbatim:

uv run skills/project/scripts/project_cli.py log <slug> <<'NOTE'
<entry text>
NOTE

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 create a new project without the user's explicit confirmation.
  • Don't force a project context onto an unrelated request.