# Remedy Specification — v0
Status: Draft, pre-freeze. Target freeze: end of Wave 1a.
Remedy is a specification for directories. This document defines what a Remedy folder is, what a .remedy file contains, and what any Remedy-aware tool MUST do when it encounters one. Tools that deviate from the MUST clauses are not “Remedy-compliant.”
# 1. Concepts
# 1.1 A Remedy folder
A Remedy folder is any directory whose root contains a single file named .remedy. The folder is the unit of Remedy; the .remedy file is the contract that tells tools how to read the folder.
A folder without a .remedy file is not a Remedy folder. Tools MUST NOT treat such a folder as if it were.
# 1.2 Sub-remedies
A Remedy folder MAY contain sub-directories that are themselves Remedy folders (each with its own .remedy). Sub-remedies are autonomous: they have their own identity, their own .remedy, and can be moved, published, or opened independently of their parent.
A sub-remedy MAY declare parent: in its .remedy, but this is advisory; the parent folder does not “own” the sub-remedy.
# 1.3 The .remedy file
- Encoding: UTF-8.
- Syntax: YAML 1.2.
- Key order: canonical (enforced by
remedy fmt; see §3). - Required top-level keys:
remedy,kind,intent,version. - Unknown top-level keys: tolerated, surfaced as warnings by
remedy lint.
# 1.4 What the .remedy file describes
- Identity — who this folder is (
remedy.id,remedy.name,remedy.domain). - Intent — what the folder is for, in 1–3 sentences of natural language. Embedded.
- Kind — what type of Remedy this is (see §4).
- File conventions — which roles map to which file extensions inside the folder (see §2.3).
- Capabilities — what features, flows, entities, integrations the folder exposes.
- Design hints — optional UI and aesthetic guidance for tools that render the folder.
- Runtime target — where this Remedy is designed to run.
- Version — semver of this Remedy (not of the spec).
# 2. The .remedy file schema
# 2.1 Canonical key order
Top-level keys, in this exact order when present:
remedy: # identity
kind: # one of: feature | tool | product | workspace | doc-set (§4)
intent: # 1–3 sentence natural-language purpose (embedded)
owners: # list of people/orgs
tags: # free tags (embedded)
entities: # domain nouns
files: # role → extension/pattern conventions (§2.3)
features: # ordered list of features (for kind: tool, product)
flows: # ordered list of user flows
integrations: # external systems touched
permissions: # role → capability matrix
ui: # optional UI hints
design: # aesthetic/brand hints
marketplace: # pricing, licence, co-creator shares (v1+)
runtime: # sovereign | web | desktop | morphee | any
parent: # advisory pointer to parent remedy (optional)
version: # semver of this remedy
Tools MUST emit in this order. remedy fmt is the reference implementation.
# 2.2 The remedy: identity block
remedy:
id: timebill.invoice-run # dot-delimited slug, globally unique within domain
name: TimeBill Invoice Run # human label
domain: timebill # root namespace (usually = product)
# 2.3 The files: block
Declares how files in the folder should be interpreted. A tool encountering a file whose role it doesn’t know MUST NOT guess; it MUST surface the file as-is.
files:
spec: { ext: .md, path: SPEC.md, required: true }
schema: { ext: .sql, path: schema.sql, required: false }
design: { ext: .md, pattern: "design/*.md", required: false }
fixtures: { ext: .yml, pattern: "fixtures/*.yml", required: false }
code: { ext: .ts, pattern: "src/**/*.ts", required: false }
Roles are strings. A small standard set is reserved (see §2.4); authors may invent new roles, which tools treat as opaque.
# 2.4 Reserved role names (v0)
spec, design, schema, fixtures, code, tests, docs, prompt, embedding-source. Tools MAY render these specially (e.g. show spec as the default preview). All other role names are opaque: surfaced, not interpreted.
# 2.5 The features: block
Used when kind: tool or kind: product. Each feature is an ordered map:
features:
- id: submit-complaint
intent: Capture a free-form complaint with optional attachments.
triggers: [ user.clicks: new-complaint ]
preconditions: [ user.authenticated ]
steps:
- collect: { subject, body, attachments? }
- classify.embed: body
- persist: complaint
- notify.operator: by-category
outputs: [ complaint.id ]
errors: [ attachment-too-large ]
tags: [ intake ]
version: 0.1.0
Step verbs are open-ended in v0. remedy lint warns on unrecognized verbs; it does not reject them. The recognized set grows as dogfoods force it.
# 2.6 The flows: block
flows:
- id: weekly-invoice-run
intent: Operator runs Friday invoicing.
steps:
- open: toggl.week-report
- review: hours-per-client
- invoke: timebill.draft-invoices
- confirm: per-invoice
- submit: xero
outputs: [ invoice.ids ]
version: 0.1.0
# 2.7 The design: block
Aesthetic and brand guidance that tools rendering this Remedy SHOULD respect:
design:
palette: petitgen-dark
typography: inter
density: comfortable
voice: "direct, technical without posturing"
Values are hints, not enforced. Desktop and Web surfaces MUST read this block; CLI tools MAY ignore it.
# 2.8 The runtime: key
One of: sovereign, web, desktop, morphee, any. A Remedy with runtime: morphee alone is invalid — Morphee is an optional surface, not a required one.
# 3. Canonical formatting
remedy fmt rewrites a .remedy file so that:
- Top-level keys appear in the canonical order (§2.1), missing keys omitted.
- Map keys inside reserved blocks (
remedy,files,features[],flows[]) appear in their canonical order (see each block’s definition). - Sequences preserve author order (they are semantically ordered).
- Indent: two spaces. No tabs.
- Block scalars
>or|for any string longer than 80 columns or containing a newline.
Tools MUST treat remedy fmt output as the canonical form. Diff review assumes canonical form on both sides.
Why key order is load-bearing. Canonical order means a given sub-object lands on the same line range across versions. git diff then points the reviewer to exactly which sub-object changed. A reordering within a sequence is itself a semantic change and diffs cleanly.
# 4. Kinds
A Remedy folder’s kind: declares what type of thing it is. v0 recognises five kinds. Tools MAY specialise rendering per kind.
| Kind | Meaning | Expected contents |
|---|---|---|
feature | One atomic feature, usually a sub-remedy of a tool or product. | .remedy, spec.md, optional design/, fixtures/. |
tool | An internal Petitgen tool (e.g. TimeBill, Admin). | .remedy with features:; sub-folders per feature. |
product | A customer-facing product (e.g. Complaintery). | Same as tool + marketplace: block. |
workspace | A container for multiple remedies (e.g. the Petitgen monorepo). | .remedy + sub-folders each their own Remedy. |
doc-set | Long-form docs, no code. | .remedy + markdown files; embedded for search. |
Kinds are fixed in v0; the taxonomy is extensible in v1.
# 5. Embeddings
Every intent:, every tags: entry, every natural-language step argument, and every file declared with role embedding-source is fed through an embedding model at build time.
# 5.1 Model
- Default:
nomic-embed-textvia local Ollama. Remedy is sovereign by default — no network required to build. - Alternate:
text-embedding-3-small(OpenAI), selected by settingREMEDY_EMBED_MODEL=openai:text-embedding-3-small. - The compiled artifact records which model produced which vector, so switching models invalidates the cache cleanly.
# 5.2 The compiled artifact
remedy build produces .remedy.compiled.json at the folder root:
{
"spec_version": "0",
"source_hash": "sha256:…",
"model": "nomic-embed-text",
"remedy": { … }, // the parsed .remedy
"embeddings": {
"intent": [ … ],
"features.submit-complaint.intent": [ … ],
…
}
}
The compiled artifact is what the Runtime, Desktop, and Web surfaces consume. Authors never hand-edit it.
# 5.3 How the runtime uses embeddings
- Routing. Ambiguous input (a complaint, an email, a chat message) is matched against feature
intent:vectors; the nearest feature handles it. - Search. Marketplace and in-app search query by vector.
- Classification. New incoming items are scored against the feature set; if no feature matches above threshold, the runtime surfaces “no feature matches — candidate for a new remedy.”
Embeddings are recomputed only when source text changes; canonical formatting keeps the cache stable.
# 6. Tooling contract
Any “Remedy-compliant” toolchain MUST provide these commands with these contracts:
| Command | Input | Output | Contract |
|---|---|---|---|
remedy fmt <path> | folder or .remedy file | rewritten file(s) | Idempotent. Semantically no-op. |
remedy lint <path> | folder | warnings/errors | Exits non-zero on schema errors; zero with warnings. |
remedy build <path> | folder | .remedy.compiled.json | Recomputes embeddings only for changed sources. |
remedy run <path> | folder | local server | Serves the compiled Remedy at localhost:. Minimum viable UI. |
remedy diff <a> <b> | two folders | feature-level diff | Ignores YAML whitespace; surfaces semantic moves. |
remedy publish | folder | marketplace listing | v1+. Not required in v0. |
All v0 commands are implemented in packages/remedy-cli/ and expose the same surface via packages/remedy-mcp/ for Claude Code.
# 7. Surfaces
Remedy the spec is surface-agnostic. v0 ships three reference surfaces:
- CLI (
remedy) — local, scriptable. Required baseline. - MCP (
remedy-mcp) — Claude Code reads/writes Remedy folders through this. - Desktop (
remedy-desktop) — Tauri Mac app. Wraps the CLI and a local web view for authoring and running Remedies. - Web (
remedy-web, hosted atremedy.build) — same web UI as Desktop, cloud-backed, accessible from any browser and embeddable inside Complaintery / Admin.
All four consume remedy-core. A fifth surface is any third-party tool that chooses to read .remedy files — this spec is the contract they target.
# 8. Versioning
# 8.1 Spec version
This document is spec v0. v0 is explicitly pre-stable: breaking changes are allowed. Each change requires:
- An entry in docs/decisions/ dated and signed.
- A bump to
spec_versionin the compiled artifact schema. - A
remedy migrate --from 0.N --to 0.Mcommand if the change breaks existing Remedies.
v1 freezes the surface. After v1, breaking changes require a major bump and a migration plan.
# 8.2 Per-Remedy version
Each Remedy carries its own version: (semver). Features within a Remedy carry their own version:. A feature’s major bumps when its steps: contract changes.
# 9. Non-goals in v0
- Marketplace. Listings, pricing, payouts — v1.
- Morphee adapter. v1+, after Remedy proves itself sovereign.
- Visual drag-drop editor. YAML-first; visual authoring is v2.
- Mobile. Desktop + web is enough for Petitgen’s use.
- Multi-tenant hosted runtime.
remedy.buildhosts the editor, not customer tenants. Customer tenants are sovereign.
# 10. Glossary
- Remedy (the spec) — this document.
- A Remedy (the noun) — any folder with a
.remedyfile at its root. - Sub-remedy — a Remedy folder nested inside another.
- Feature — an entry under
features:, either inline in the.remedyor as a sub-remedy ofkind: feature. - Compiled artifact —
.remedy.compiled.json, produced byremedy build, consumed by runtimes. - Surface — any tool that speaks Remedy (CLI, Desktop, Web, MCP, third-party).