This is a template repo for building Python-first web applications and deploying them to Docker.
MANDATORY: Before doing ANY work that involves code or planning on code, you MUST call get_se_overview() to load the software engineering process. Do this at the start of every conversation. No exceptions.
This project uses external CLI tools for configuration and database management. Their agent instructions are canonical — when in doubt, run the agent command to get up-to-date instructions rather than relying solely on the docs in this repo.
| Tool | Purpose | Agent instructions |
|---|---|---|
| dotconfig | Secrets & .env configuration (SOPS + age encryption, layered env files) |
dotconfig agent |
| rundbat | Dev/prod database lifecycle (Docker Postgres containers, credentials) | rundbat mcp --help |
| clasi | SE process management (sprints, tickets, architecture) | get_se_overview() MCP tool |
When working with secrets or .env files, follow dotconfig agent
instructions. When working with database containers or connection
strings, use the rundbat MCP tools (available via .mcp.json).
The docs below provide project-specific context but must not conflict
with the tool instructions above — if they do, the tool instructions win.
Human-facing docs live in docs/. Consult them for reference:
- docs/setup.md — First-time checkout, install script, dev server
- docs/template-spec.md — Technology decisions, project structure, conventions
- docs/deployment.md — Production builds, deployment
- docs/secrets.md — Secrets inventory and onboarding
- docs/testing.md — Full test strategy and patterns
Agent behavioral rules are in .claude/rules/ (auto-loaded):
testing.md— Test conventions, pytest fixtures, async testsarchitecture.md— Router/service pattern, htmx/Alpine philosophy, DB migration pathsecrets.md— Secrets handling, security rules, config structurerundbat.md— Database and deployment MCP tools
MANDATORY: Before doing ANY work that involves code or planning on code, you MUST call get_se_overview() to load the software engineering process. Do this at the start of every conversation. No exceptions.
This project uses the CLASI (Claude Agent Skills Instructions) software engineering process, managed via an MCP server.
The SE process is the default. Any activity that results in changes to the codebase — or plans to change the codebase — falls under this process. Follow it unless the stakeholder explicitly says "out of process" or "direct change".
Activities that trigger the SE process include:
- Building a new feature or adding functionality
- Fixing a bug or resolving an issue
- Refactoring, restructuring, or reorganizing code
- Writing, updating, or removing tests
- Updating documentation that describes code behavior
- Planning, scoping, or designing an implementation
- Reviewing code or architecture
- Creating, modifying, or closing sprints and tickets
- Merging, branching, or tagging releases
If it touches code, tests, docs about code, or plans for code — STOP.
Call get_se_overview() if you haven't already. Then either follow the
process it describes, or confirm the stakeholder has explicitly said
"out of process" or "direct change" before proceeding without a sprint.
Before writing ANY code, you MUST confirm one of:
- You have an active sprint and ticket — check with
list_sprints()andlist_tickets(). If you do, execute that ticket. - The stakeholder has explicitly said "out of process", "direct change",
or invoked
/oop. If so, proceed without a sprint.
If neither is true, do NOT write code. Instead, enter the SE process:
use get_skill_definition("plan-sprint") to create a sprint, or
get_skill_definition("next") to determine the correct next step.
Before using any generic tool for a process activity, check
list_skills() for a CLASI-specific skill. CLASI skills always take
priority over generic tools for process activities.
Examples of what this means:
- Creating a TODO → use the CLASI
todoskill, not theTodoWritetool - Finishing a sprint → use
close-sprintskill, not generic branch tools - Creating tickets → use
create-ticketsskill, not ad-hoc file creation
When a required MCP tool or process step is unavailable or fails, STOP and report the failure to the stakeholder. Do not:
- Create substitute artifacts that bypass the process
- Improvise workarounds outside the established workflow
- Silently continue without the required tool
The correct response is: "Tool X is unavailable. I cannot proceed without it. Let's fix the MCP connection first."
Work happens at two levels: project initiation and sprints.
Project initiation (once per project):
- Interview the stakeholder to understand the project goals and scope.
→
get_skill_definition("project-initiation") - Generate project initiation documents (overview, spec, use cases).
→
get_skill_definition("elicit-requirements") - Break the project into sprints — either all at once if the spec is
complete, or incrementally (one or two sprints at a time) so the
stakeholder can adjust later sprints as the project evolves.
→
get_skill_definition("plan-sprint")
Sprint lifecycle (repeated per sprint):
- Mine TODOs — Scan
docs/clasi/todo/withlist_todos()for ideas relevant to the sprint. Discuss with the stakeholder. - Create sprint —
create_sprint(title)sets up the directory and registers the sprint. Create the branch:git checkout -b sprint/NNN-slug. - Write planning docs — Fill in
sprint.md,usecases.md, and updatearchitecture.mdin the sprint directory with real content. The architecture doc is copied from the previous sprint — update it to reflect the target end-of-sprint state and fill in Sprint Changes. - Architecture review —
advance_sprint_phase(sprint_id)to move to architecture-review. Delegate to the architecture-reviewer agent. Record the result:record_gate_result(sprint_id, "architecture_review", "passed"). - Stakeholder review — Present the plan to the stakeholder.
record_gate_result(sprint_id, "stakeholder_approval", "passed"). - Create tickets —
advance_sprint_phase(sprint_id)to ticketing. Usecreate_ticket(sprint_id, title)for each ticket. Fill in details. - Execute tickets —
advance_sprint_phase(sprint_id)to executing.acquire_execution_lock(sprint_id). Execute each ticket viaget_skill_definition("execute-ticket"). - Close sprint — After all tickets are done, use
get_skill_definition("close-sprint")to merge, archive, and tag.
Use /se or call get_se_overview() for full process details and MCP
tool reference.
Agents MUST complete these steps. No exceptions. No skipping.
Agents have repeatedly failed to move tickets to done and close sprint branches. This creates inconsistent state. These rules are non-negotiable.
After finishing a ticket's code changes, you MUST:
- Run the full test suite and confirm all tests pass.
- Set ticket
statustodonein YAML frontmatter. - Check off all acceptance criteria (
- [x]). - Move the ticket file to
tickets/done/— usemove_ticket_to_done. - Move the ticket plan file to
tickets/done/if it exists. - Commit the moves:
chore: move ticket #NNN to done.
Finishing the code is NOT finishing the ticket. The ticket is not done
until the file is in tickets/done/ and committed.
After finishing all tickets in a sprint, you MUST close the sprint:
- Merge the sprint branch into main.
- Call
close_sprintMCP tool (archives directory, releases lock). - Commit the archive.
- Push tags (
git push --tags). - Delete the sprint branch (
git branch -d sprint/NNN-slug).
Never merge a sprint branch without archiving the sprint directory. Never leave a sprint branch dangling after the sprint is closed.
When the stakeholder corrects your behavior or expresses frustration ("that's wrong", "why did you do X?", "I told you to..."):
- Acknowledge the correction immediately.
- Run
get_skill_definition("self-reflect")to produce a structured reflection indocs/clasi/reflections/. - Continue with the corrected approach.
Do NOT trigger on simple clarifications, new instructions, or questions about your reasoning.
This project uses rundbat to manage Docker-based deployment environments. rundbat is an MCP server that handles database provisioning, secret management, and environment configuration.
If you need a database, connection string, deployment environment, or anything involving Docker containers or dotconfig — use the rundbat MCP tools. Do not run Docker or dotconfig commands directly.
Run rundbat mcp --help for the full tool reference, or call
discover_system to see what is available.
| Tool | Purpose |
|---|---|
discover_system |
Detect OS, Docker, dotconfig, Node.js |
init_project |
Initialize rundbat in a project |
create_environment |
Provision a database environment |
get_environment_config |
Get connection string (auto-restarts containers) |
set_secret |
Store encrypted secrets via dotconfig |
start_database / stop_database |
Container lifecycle |
health_check |
Verify database connectivity |
validate_environment |
Full environment validation |
check_config_drift |
Detect app name changes |
Configuration is managed by dotconfig. Run dotconfig agent for full
documentation on how dotconfig works. Key locations:
config/rundbat.yaml— Project-wide rundbat config (app name, naming templates)config/{env}/secrets.env— SOPS-encrypted credentialsconfig/keys/— SSH keys (encrypted via dotconfig key management)