What is CatThatCopies?
A foundry for skills that can prove what they do
CatThatCopies turns a purpose, curated references, and a representative task into a tested, versioned agent skill. The browser is the human control plane. A connected local agent constructs the candidate and runs the real test through MCP. A human reviews the evidence and publishes the immutable version.
CatThatCopies does not host a model or pretend that generated output came from the server. Construction happens in your agent environment, while the service records the exact project revision, candidate checksum, test output, provenance, and publication decision.
make app
# Open https://cathatcopies.localhost
make backend-test
What do I need before I start?
Requirements
- Node.js 22.13 or newer for the built-in SQLite driver.
- npm and Make for the repository commands.
- A browser for the workbench.
- An OAuth-capable MCP client such as Codex for agent construction.
- Docker and the Compose plugin only when deploying the supplied VPS stack.
Local development uses Portless, so you do not choose frontend or backend ports. The stable product origin is normally https://cathatcopies.localhost.
How do I run and verify the app locally?
Local development
From the repository root, install dependencies if needed and start the complete app:
npm install
make app
Portless prints the stable URL. The frontend, browser auth, OAuth callbacks, HTTP API, and MCP endpoint all share that origin. Useful checks:
make backend-test
npm run build
npm run test:e2e
Open /backend-status to inspect backend health from the product UI, or request /healthz directly for SQLite, artifact storage, and free-disk readiness.
Development rate limiting is off by default because browser and test traffic share localhost. Set
CATHAT_RATE_LIMIT_ENABLED=trueonly when you need to test limiter behavior.
What is the shortest path to a published skill?
Your first skill
- Create an account and save the generated 16-digit account number.
- Open Editorial illustrations · System default in the skill library.
- Choose Create your version. The immutable example is copied into an account-owned project.
- Edit the purpose or representative input, curate references, and save the project.
- Connect Codex, copy the prompt from section 03, and let the agent submit a candidate plus real test output.
- Review the candidate state, validation, output, and reference-adherence evidence.
- Choose Publish version. The published version becomes immutable and is promoted to
stableby default.
The workbench only enables publication after a saved project has a passing representative test for the current candidate.
What exactly is saved in a project?
The project is the construction contract
Every editable project has an optimistic numeric revision and four behavior-defining inputs:
| Field | What it controls |
|---|---|
| Name and slug | Human identity and stable resource address |
| Purpose | The behavior the constructed skill must provide |
| Representative input | The real task the agent must execute |
| Success criteria | The human-readable bar for the submitted result |
| Expected output | Whether the test must return an image or readable text |
Saving increments the revision. Agent construction claims an exact revision; if you change the project after a claim, the old build cannot silently publish the new intent. The generated agent prompt includes the project contract and current reference requirements.
How should I curate visual references?
References teach the intended visual system
Upload PNG, JPEG, WebP, or SVG files in section 02. The workbench accepts up to 12 images for its current visual workflow. Mark up to three as top references when they are essential to the identity.
Top references create a stronger construction contract. The agent must:
- Read their metadata and checksums through MCP.
- Materialize the exact bytes into local checksum-keyed files.
- Inspect each reference visually.
- Attach all required files to image generation.
- Record reference-inspection and reference-adherence provenance.
Metadata or prose descriptions alone are not accepted as proof of visual inspection. Generated image output can be saved back into the project as a new reference for the next revision.
What does the connected agent do?
Agent construction lifecycle
saved revision → claim lease → submit files → validate → run real test → submit output → complete
The agent claims a 15-minute lease for the exact draft revision, submits candidate files, receives deterministic validation, runs the representative task in its own environment, and uploads the real output plus provenance. Candidate files normally include SKILL.md and may include agent metadata, scripts, references, or other assets.
Open the CatThatCopies project prompt I provide and build the exact saved revision.
Materialize and visually inspect every required top reference before generating. Submit the candidate files, run the representative test locally, upload the real output with provenance, and complete the build. Do not publish; publication requires my approval in the workbench.
Required SKILL.md structure includes frontmatter fields name and description, plus a Purpose heading. Image projects with top references also encode the required checksums and visual invariants. Failed validation or a failed representative test keeps publication locked.
What happens when I publish?
Publication is an explicit human action
A connected agent cannot publish. The workbench requires a passing test, the current project revision, an explicit approval, a unique numeric version such as 1.0, and an idempotency key.
One short transaction records the immutable version, constructed files, complete project snapshot, ordered references, representative input and output, provenance, notes, and checksum. New publications are promoted to stable by default.
Published files and snapshots are protected by database triggers. Moving stable changes only the channel pointer; it never rewrites or deletes a version.
How do stable, exact versions, rollback, and forks work?
Version center
The workbench lists immutable versions newest first and distinguishes Default (the current stable target) from Latest (the newest publication). From each row you can inspect details, compare with the previous version, copy an exact URI, download a ZIP, or fork the historical snapshot.
| Action | Result |
|---|---|
| Make default | Moves stable to the selected exact version after confirmation |
| Restore latest | Points stable back to the newest publication |
| Fork | Creates a new editable project from the selected immutable snapshot |
| Download ZIP | Exports that exact version with its checksum-bearing manifest |
Rollback is therefore a pointer change, not destructive history editing. An exact address such as skill://my-skill/1.2/SKILL.md always keeps the same bytes.
How do I connect Codex to CatThatCopies?
Connect Codex once
Run these commands while the app is available at the shown origin:
codex mcp add catthatcopies --url https://cathatcopies.localhost/mcp
codex mcp login catthatcopies --scopes skills:read,builds:write,tests:write
The login command opens OAuth authorization in your browser. Authenticate with the same 16-digit account number used by the workbench and approve the requested scopes. CatThatCopies gives the client short-lived access tokens and rotating refresh tokens; the account number itself is never shared with the MCP client.
If Portless prints a different shared proxy port, use that exact origin. The setup commands inside section 03 are generated from the current browser origin.
How should an agent consume a published skill?
Resolve once, then pin the exact result
Use stable to discover the current default, but do not keep following the channel during an active task:
Resolve skill://editorial-illustrations/stable/manifest once.
Pin the returned exact version and checksum for this task, read its SKILL.md, and follow that immutable version even if stable changes later.
skill_resolve returns an exact version and checksum. Retain both for the task, then read exact resources such as:
skill://editorial-illustrations/1.0/SKILL.md
skill://editorial-illustrations/1.0/agents/openai.yaml
This prevents a later default-version change from altering behavior halfway through the work.
Which MCP operations are available?
MCP reference
| Group | Operations |
|---|---|
| Discover | skills_list, skill_get, skill_versions, skill_resolve |
| Read | resources/list, resources/read, exact skill:// resources |
| Construct | project_get, reference_get, build_claim, skill_submit |
| Test | skill_validate, test_get, test_submit, build_complete |
| Portability | skill_export, skill_feedback |
The endpoint is POST /mcp and uses stateless Streamable HTTP JSON-RPC. Clients can dynamically register, must use authorization code with PKCE S256, and receive only the scopes approved during browser consent. Write operations use leases or idempotency keys where retries could otherwise duplicate state.
What are the important HTTP endpoints?
HTTP control plane
| Method and path | Purpose |
|---|---|
POST /api/accounts |
Create an anonymous account and receive its credential once |
POST /api/sessions |
Exchange the account number for a browser session |
GET /api/me |
Read the session account and CSRF token without caching |
GET /api/skills |
List skills visible to the account |
GET /api/skills/:slug |
Read the current project, references, build, prompt, and versions |
PATCH /api/skills/:slug |
Save an owned draft with its expected revision |
POST /api/skills/:slug/references |
Add a content-addressed project reference |
GET /api/skills/:slug/compare |
Compare two exact version snapshots |
GET /api/skills/:slug/versions/:version/export |
Export a portable exact-version ZIP |
GET /api/connections |
List authorized MCP clients and last activity |
DELETE /api/connections/:id |
Revoke a client and all of its tokens immediately |
GET /api/audit-events |
Read append-only lifecycle and security events |
Browser state changes require the HTTP-only session cookie and X-CSRF-Token. Publication and historical forks additionally require an Idempotency-Key header. See backend/README.md in the repository for the full route contract.
How do accounts and credentials work?
Anonymous accounts with one durable credential
Account creation produces a uniformly generated 16-digit number. Save it immediately: there is no email address and no recovery flow.
- SQLite stores an HMAC lookup, never the account number itself.
- The server-side login pepper is required to verify a login.
- An active HTTP-only session stores an AES-GCM-encrypted copy so the workbench can show a redacted number and copy the full credential.
- Logging out deletes that session copy; expired sessions are purged.
- OAuth clients receive revocable tokens, not the account number.
Losing the production login pepper makes all existing account numbers unusable. Preserve it outside the application VPS and restore the exact same value with the data backup.
Which environment variables matter?
Configuration
| Variable | Default | Purpose |
|---|---|---|
CATHAT_PUBLIC_URL |
Local host and port | Public origin used by OAuth metadata and redirects |
CATHAT_HOST |
127.0.0.1 |
Backend bind address |
CATHAT_PORT |
8787 |
Backend fallback port; Portless normally assigns one |
CATHAT_DATA_DIR |
backend/data |
SQLite, artifacts, and local backups |
CATHAT_LOGIN_PEPPER |
Development placeholder | Permanent secret used for account-number lookup |
CATHAT_TRUST_PROXY |
false |
Trust the first forwarded address for rate limiting |
CATHAT_RATE_LIMIT_ENABLED |
Off in development | Enable in-memory request buckets |
CATHAT_MAX_SKILLS_PER_ACCOUNT |
50 |
Skill quota |
CATHAT_MAX_REFERENCES_PER_SKILL |
30 |
Backend reference quota |
CATHAT_MAX_BUILDS_PER_SKILL |
100 |
Build quota |
CATHAT_MAX_ACCOUNT_STORAGE_BYTES |
262144000 |
Account artifact quota |
CATHAT_MIN_FREE_DISK_BYTES |
536870912 |
Health-check free-space floor |
Production requires HTTPS and a login pepper of at least 32 characters. Only enable CATHAT_TRUST_PROXY=true when the backend port is private behind a trusted reverse proxy, as it is in the supplied Compose deployment.
How do I deploy, back up, and restore CatThatCopies?
Single-node VPS deployment
Create the production environment file, set the domain, public URL, and a permanent pepper, then deploy:
cp .env.production.example .env
# Edit .env, then:
make production
Caddy provisions HTTPS, serves the built workbench, and routes API, OAuth, and MCP requests to the single backend process. Keep one backend writer per SQLite volume.
Verified backup
BACKUP_DEST=/path/on/a/separate/disk make production-backup
The backup uses SQLite's online API, copies immutable artifacts, and writes a SHA-256 inventory. Replicate the destination off the VPS; a backup on the application host alone is not disaster recovery.
Restore
- Stop the backend and preserve the failed data directory.
- Copy the selected
cathatcopies.sqlite3andartifactsinto a clean data directory. - Restore the exact production login pepper.
- Start the backend, check
/healthz, and run the contract suite against a non-production copy first.
make production-down stops the containers without deleting the named SQLite and Caddy volumes.