{ "$schema_version": 1, "parent_repo": "paperclipai/paperclip", "watchers": [ { "name": "cli-commands", "parent_paths": [ "cli/src/commands/**/*.ts", "cli/src/index.ts" ], "docs_paths": [ "docs/reference/cli/**" ], "tier": "pr", "detect": "New or renamed command names from `program.command()` / Commander definitions. New or removed flags from `.option()`. Argument signature changes. Help-text changes." }, { "name": "env-vars", "parent_paths": [ ".env.example", "server/src/config.ts", "packages/**/env.ts", "packages/**/config.ts" ], "docs_paths": [ "docs/reference/deploy/environment-variables.md" ], "tier": "auto-merge", "detect": "Lines matching `^[A-Z_][A-Z0-9_]*=` in .env.example; `process.env.X` reads; zod env schema fields. Append-only edits are auto-merge; renames/removals escalate to PR tier." }, { "name": "rest-routes", "parent_paths": [ "server/src/routes/**/*.ts" ], "docs_paths": [ "docs/reference/api/**" ], "tier": "pr", "detect": "Route registrations (`app.get/post/put/delete`, fastify `route({...})`). New route file = new doc page; signature/payload changes = update existing page." }, { "name": "adapters", "parent_paths": [ "packages/adapters/**", "packages/plugins/sandbox-providers/**" ], "docs_paths": [ "docs/reference/adapters/**" ], "tier": "pr", "detect": "Files under packages/adapters//** or packages/plugins/sandbox-providers//** signal adapter changes. The at depth 1 identifies the adapter. New top-level dir = candidate new adapter — but first consult scripts/sync/detect-renames.mjs to confirm it's not a directory rename. Rename = update existing doc page in place with change_kind: renamed; genuinely-new = create a new page mirroring the neighbour pattern. Manifest (`package.json`, `adapter.json`) changes = update existing page." }, { "name": "plugin-sdk", "parent_paths": [ "packages/plugins/sdk/src/index.ts", "packages/plugins/sdk/src/**/*.ts" ], "docs_paths": [ "docs/reference/plugins/sdk.md", "docs/administration/plugins.md" ], "tier": "pr", "detect": "Public API surface of the plugin SDK — exported types/functions from src/index.ts. The reference page (docs/reference/plugins/sdk.md) is the canonical home; docs/administration/plugins.md may need touch-ups when the operator-facing usage flow changes. (If the SDK package dir itself is renamed, consult scripts/sync/detect-renames.mjs before treating the new path as a fresh surface.)" }, { "name": "agent-skills", "parent_paths": [ "skills/**" ], "docs_paths": [ "docs/reference/skills.md", "docs/how-to/write-a-company-skill.md" ], "tier": "pr", "detect": "Any file under skills/** in parent — these are canonical skill bundles. New top-level dir under skills/ = candidate new skill bundle (consult scripts/sync/detect-renames.mjs to confirm it's not a rename of an existing bundle before creating a new doc entry); mention in the skills reference. Changes inside an existing bundle = update the tutorial or reference as appropriate. The plugin SDK is a separate concern — see the plugin-sdk watcher. The app-shipped skills catalog is a separate concern — see the skills-catalog watcher." }, { "name": "skills-catalog", "parent_paths": [ "packages/skills-catalog/catalog/**/SKILL.md", "packages/skills-catalog/generated/catalog.json" ], "docs_paths": [ "docs/reference/skills.md", "docs/guides/org/skills.md" ], "tier": "pr", "detect": "The app-shipped skills catalog — installable bundled/optional skills, distinct from the server-forced bundled skills under skills/** (covered by the agent-skills watcher). Skill bundles live at packages/skills-catalog/catalog/{bundled,optional}///SKILL.md; packages/skills-catalog/generated/catalog.json is the generated manifest of catalog membership and metadata. A new SKILL.md under catalog/ = candidate new catalog skill — consult scripts/sync/detect-renames.mjs before treating a moved bundle as brand-new. Document new or changed catalog skills in the Skills reference (app-shipped catalog section) and the org Skills guide. catalog.json churn alone (reorder/regen) without a SKILL.md change is usually context-only." }, { "name": "schemas", "parent_paths": [ "packages/**/schema/*.ts", "packages/**/*.schema.ts" ], "docs_paths": [ "docs/reference/**", "docs/administration/**" ], "tier": "pr", "detect": "Zod / drizzle schema field additions, removals, or type changes on entities surfaced in docs (companies, agents, issues, routines, approvals, secrets)." }, { "name": "web-ui", "parent_paths": [ "ui/src/**" ], "docs_paths": [ "docs/user-guides/**", "docs/guides/**" ], "tier": "pr", "detect": "UI component changes that may invalidate screenshots or end-user-facing guide flows. Cross-reference with screenshot registry depends_on entries before writing doc edits." }, { "name": "server-services", "parent_paths": [ "server/src/services/**" ], "docs_paths": [ "docs/administration/**", "docs/reference/api/**" ], "tier": "pr", "detect": "Business logic changes that surface behavioural shifts users will notice (e.g. how agents interact, how approvals flow). Only produce doc edits when the change has user-visible effects, not pure refactors." }, { "name": "server-adapters", "parent_paths": [ "server/src/adapters/**" ], "docs_paths": [ "docs/reference/adapters/**" ], "tier": "pr", "detect": "Server-side adapter integrations (distinct from packages/adapters/*, which are the standalone adapter packages). Often relates to how the server hosts/proxies adapter capabilities. New top-level dir under server/src/adapters/ = candidate new integration — consult scripts/sync/detect-renames.mjs before creating a new doc page." }, { "name": "db-migrations", "parent_paths": [ "packages/db/src/migrations/**" ], "docs_paths": [ "docs/administration/**", "docs/reference/deploy/database.md" ], "tier": "context-only", "detect": "Migrations themselves rarely need user-facing docs, but a sudden burst of migrations often correlates with a schema change watched elsewhere. Use this watcher's hits as context only — never produce edits directly. Deliberately NOT promoted above context-only: most migrations are columns, indexes, and renames that need no prose, and promoting this would put all of them in front of a human for triage. The gap that would justify revisiting is a migration changing user-visible behaviour WITHOUT touching a packages/**/schema/*.ts file the `schemas` watcher already catches — a data backfill that changes a default, a retention window, or a constraint that starts rejecting input that used to be accepted." }, { "name": "release-channels", "parent_paths": [ "doc/CHANNELS.md", "cli/src/commands/channels.ts" ], "docs_paths": [ "docs/how-to/update-paperclip.md", "docs/reference/cli/installation.md" ], "tier": "pr", "detect": "The release-channel model (canary → nightly → beta → stable), its npm dist-tags and Docker image tags, and the `paperclipai channels` command. `doc/CHANNELS.md` is the authoritative parent guide; `channels.ts` holds the RELEASE_CHANNELS descriptors and the version→channel regexes. Changes here (a new lane, a dist-tag rename, the `:latest`-tracks-stable semantics) must flow into the channels sections of update-paperclip.md and the CLI installation page. Note: channels.ts is also matched by the cli-commands watcher — dedupe by surface, don't emit twice.", "channel_context": "Docs ship on the STABLE lane only. Do not describe beta/nightly/canary versions as the release; they are npm/Docker artifacts with no git tag. See maintenance/release-channels-plan.md." }, { "name": "release-notes", "source": "github-releases", "parent_paths": [], "docs_paths": ["docs/**"], "tier": "context-only", "detect": "Fetched via `gh release view ` to give other watchers framing/intent. Never produces edits directly — release notes are reference data, not source." } ], "adapter_doc_sources": { "$comment": "Maps a doc basename (docs/reference/adapters/.md) to the source paths the verifier should search. Use when the doc name does not match the adapter package directory under packages/adapters/. Without an entry here, verify-edit.mjs finds no sources and reports every adapter-config-field on the page as unverified — a silent false negative that fires on every run, not a one-off.", "hermes-local": ["packages/adapters/hermes"], "hermes-gateway": ["packages/adapters/hermes"], "claude-code": ["packages/adapters/claude-local"], "codex": ["packages/adapters/codex-local"], "gemini-cli": ["packages/adapters/gemini-local"], "kimi-local": ["packages/adapters/kimi-local"], "opencode": ["packages/adapters/opencode-local"], "pi": ["packages/adapters/pi-local"], "http": ["server/src/adapters/http"], "process": ["server/src/adapters/process"], "modal": ["packages/plugins/sandbox-providers/modal"], "sandbox-providers": ["packages/plugins/sandbox-providers"] }, "screenshot_registry": "docs/user-guides/screenshots/registry.json", "quarantine_hours": 24, "auto_merge_safety": { "max_files_changed": 1, "max_lines_changed": 50, "require_tier": "auto-merge", "forbid_kinds": ["removed", "renamed"], "$comment": "forbid_kinds blocks auto-merge for destructive changes regardless of size. A 1-line rename is still a breaking change and demands human review. max_lines_changed=50 accommodates real-world env-vars batch additions (e.g. a new feature shipping with 10–20 related env vars and their inline comments in .env.example)." }, "$notes": { "no_skip_patterns": "We deliberately do NOT filter commits by message regex (e.g. ^revert, ^[codex]). The diff window is cumulative (last_release_tag → HEAD) so reverts are already net-zero in the manifest. Filtering by message would HIDE the undo signal — if we processed an original commit and then skipped its revert, docs would stay wrong forever. The proper filter is surface impact via watcher path globs.", "quarantine_still_needed": "Quarantine handles the race where a feature lands but its revert hasn't yet. Without it, we'd churn doc edits that get undone the next day." } }