§ specification

A protocol for folders.

Reading time ~10 minutes. Every MUST clause is a compliance test for tools. Raw source at SPEC.md .

status
pre-stable — breaking changes allowed
version
0
freeze
after v1 (TBD)
modifications
require a dated ADR under /decisions

# 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

  1. Identity — who this folder is (remedy.id, remedy.name, remedy.domain).
  2. Intent — what the folder is for, in 1–3 sentences of natural language. Embedded.
  3. Kind — what type of Remedy this is (see §4).
  4. File conventions — which roles map to which file extensions inside the folder (see §2.3).
  5. Capabilities — what features, flows, entities, integrations the folder exposes.
  6. Design hints — optional UI and aesthetic guidance for tools that render the folder.
  7. Runtime target — where this Remedy is designed to run.
  8. 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:

  1. Top-level keys appear in the canonical order (§2.1), missing keys omitted.
  2. Map keys inside reserved blocks (remedy, files, features[], flows[]) appear in their canonical order (see each block’s definition).
  3. Sequences preserve author order (they are semantically ordered).
  4. Indent: two spaces. No tabs.
  5. 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.

KindMeaningExpected contents
featureOne atomic feature, usually a sub-remedy of a tool or product..remedy, spec.md, optional design/, fixtures/.
toolAn internal Petitgen tool (e.g. TimeBill, Admin)..remedy with features:; sub-folders per feature.
productA customer-facing product (e.g. Complaintery).Same as tool + marketplace: block.
workspaceA container for multiple remedies (e.g. the Petitgen monorepo)..remedy + sub-folders each their own Remedy.
doc-setLong-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-text via local Ollama. Remedy is sovereign by default — no network required to build.
  • Alternate: text-embedding-3-small (OpenAI), selected by setting REMEDY_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:

CommandInputOutputContract
remedy fmt <path>folder or .remedy filerewritten file(s)Idempotent. Semantically no-op.
remedy lint <path>folderwarnings/errorsExits non-zero on schema errors; zero with warnings.
remedy build <path>folder.remedy.compiled.jsonRecomputes embeddings only for changed sources.
remedy run <path>folderlocal serverServes the compiled Remedy at localhost:. Minimum viable UI.
remedy diff <a> <b>two foldersfeature-level diffIgnores YAML whitespace; surfaces semantic moves.
remedy publishfoldermarketplace listingv1+. 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:

  1. CLI (remedy) — local, scriptable. Required baseline.
  2. MCP (remedy-mcp) — Claude Code reads/writes Remedy folders through this.
  3. Desktop (remedy-desktop) — Tauri Mac app. Wraps the CLI and a local web view for authoring and running Remedies.
  4. Web (remedy-web, hosted at remedy.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_version in the compiled artifact schema.
  • A remedy migrate --from 0.N --to 0.M command 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.build hosts the editor, not customer tenants. Customer tenants are sovereign.

# 10. Glossary

  • Remedy (the spec) — this document.
  • A Remedy (the noun) — any folder with a .remedy file at its root.
  • Sub-remedy — a Remedy folder nested inside another.
  • Feature — an entry under features:, either inline in the .remedy or as a sub-remedy of kind: feature.
  • Compiled artifact.remedy.compiled.json, produced by remedy build, consumed by runtimes.
  • Surface — any tool that speaks Remedy (CLI, Desktop, Web, MCP, third-party).