Skip to content

Agent rules

Laws: CONSTITUTION.md. Product: docs/. How we work: CONTRIBUTING.md. If a behavior is missing from a product page, add it in the same change or stop.

When the constitution changes, update this file in the same change.

Writing

Use simple technical English and common words. Do not invent names for things that already have names. Do not invent features.

Docs, README, and the MkDocs site use complete sentences and enough explanation that a new reader can set up and use the API without guessing. Short choppy fragments are wrong for docs. Tables are still good for endpoints, env vars, and fields.

Issues can be as long as they need to be. Include known implementation details. Do not squeeze the goal. Pull request bodies and commit messages stay short.

Code comments stay omitted unless asked.

Map

Path What
src/apipi/api/ HTTP routes
src/apipi/gateway/ Gateway handle, auth, errors, middleware, schemas
src/apipi/services/ Session/Agent/Vault/File/Skill/Model/Usage services and EventHub
src/apipi/worker/ Worker control, execution adapters, Pi harness, isolation
src/apipi/store/ Durable store and object blobs
src/apipi/env/ Computer and hosted/self_hosted environments
src/apipi/mcp/ HTTP and stdio MCP
docs/ Product and operator docs. Read the page for the part you are changing.
specs/decisions/ ADRs. Read when the architecture changes.
tests/api/ Public HTTP
tests/unit/ Internals, mocks
tests/e2e/ Live Pi
tests/support/ FakeHarness, fakes

Before code, read the docs/ page for the part you are changing.

Stack

Python 3.13, FastAPI, SQLite (one process) or Postgres (shared store). uv only. PyPI name geki-apipi; import and CLI apipi. Pi via RPC, one process per session. Run mode APIPI_RUN_MODE (none | chat | microvm, or package.mod:Class). Process default none. Production SaaS/enterprise is microvm for computers and chat for chat fleets. none is local/dev only. microvm probes a real sandbox before the API listens, then exits if it cannot start. Custom backends that set needs_probe do the same. No silent fallback. host and jail are not valid. OpenAI-compatible base_url. No Node in the gateway.

Do not

  • A second harness in this version
  • First-party search or a browser engine in the gateway
  • Silent fallback between run modes
  • ChatKit, workflow canvases, /v1/runners
  • Pi types in HTTP
  • Pi JSONL as the database
  • Accept multi_agent silently
  • A Job or cron engine, or a Slack or Teams gateway
  • Gateway auth bearers in the browser or in Postgres. MCP vault tokens may be stored tenant-scoped; GET never returns them; guests never see them.
  • Rewrite the event log
  • A custom docs frontend
  • An old copy of a decision file
  • pip, python -m venv, or pre-commit hooks
  • MkDocs or docs deps in the apipi package

Do

  • Change CONSTITUTION.md rarely. Edit in place. No amendment log.
  • Tenant-scope every query. Auth is a callback; do not store gateway bearers.
  • Keep domain logic in services and the store. HTTP only routes, validates, and serializes. Extenders call those services.
  • Persist the public event before SSE
  • Fail unknown OpenAI fields clearly
  • Pin Pi when touching the adapter
  • Warn at startup when run mode is none
  • Idle Pi TTL default 15 minutes (APIPI_IDLE_TTL)
  • uv for all Python (uv sync, uv run, uv lock)
  • Before commit: ./scripts/check. Add --docs if docs changed. Do not commit if checks fail. GitHub CI is fast (pytest -m "not slow").

Workflows

How to plan, file issues, implement, review, and release lives in .agents/skills/. Read those files. Do not copy them here.

Skill When
plan Plan work and file issues
create-issue File one GitHub issue
work-issue Do one change and open a PR
review Review a PR
release Tag origin/main for PyPI and a GitHub Release

An issue is common, not required. One checkout is one branch. Parallel work is best effort when files do not overlap. Use another folder (git worktree) or another session.

Git

CONTRIBUTING.md. Short-lived branch from main (issue-<n>-<slug>, or a short name if there is no issue). One change per PR. Rebase, squash, delete the branch. Commit when asked to implement, commit, or open a PR. Merge only when the user asks to merge. Default: return the PR URL. Never force-push main.