{"$schema":"https://meshkore.com/standard.schema.json","name":"MeshKore Standard","version":"30.0.0","updated":"2026-07-05","canonical_url":"https://meshkore.com/standard","canonical_md":"https://meshkore.com/standard.md","rule":"If anything elsewhere contradicts this document, this document wins.","folder_layout":{"root":".meshkore/","entries":[{"path":"public/","committed":true,"purpose":"identity, type, admission, members, modules (cluster.yaml + README.md + AGENT_INSTRUCTIONS.md). Always committed; since v27 docs/, modules/ and roadmap/initiatives/ are committed too (see gitignore_contract)."},{"path":"public/cluster.yaml","committed":true,"purpose":"cluster identity + admission + modules (see schema 'cluster_yaml')"},{"path":"public/README.md","committed":true,"purpose":"how to join this cluster (human-readable)"},{"path":"docs/","committed":true,"purpose":"cross-cutting docs: architecture / product / conventions / deploy / security / ops"},{"path":"docs/INDEX.md","committed":true,"purpose":"map only, no prose (R6)"},{"path":"docs/governance.md","committed":true,"purpose":"thin pointer to https://meshkore.com/standard — never a duplicated copy"},{"path":"modules/<id>/","committed":true,"purpose":"per-module bucket: README + tasks + log + diagrams"},{"path":"modules/<id>/tasks/<ID>-<slug>.md","committed":true,"purpose":"active tasks for this module"},{"path":"modules/<id>/log/<YYYY-MM>/","committed":true,"purpose":"archived (done) tasks, monthly buckets"},{"path":"modules/<id>/diagrams/","committed":true,"purpose":"mermaid sources next to the doc they illustrate"},{"path":"roadmap/state.json","committed":false,"generated":true,"purpose":"built by roadmap-build.py; never hand-edit"},{"path":"roadmap/state.js","committed":false,"generated":true,"purpose":"same as state.json wrapped as JS for the architect"},{"path":"roadmap/initiatives/<id>.md","committed":true,"purpose":"cross-module initiatives (see schema 'initiative_frontmatter')"},{"path":"timeline/<YYYY-MM-DD>.jsonl","committed":false,"generated":true,"purpose":"one event per line, UTC, append-only"},{"path":"log/<YYYY-MM-DD>.md","committed":false,"purpose":"human prose session log (local date)"},{"path":"agents/<id>.yaml","committed":false,"purpose":"per-machine agent identity"},{"path":"credentials/","committed":false,"purpose":"secrets, mode 0600"},{"path":"scripts/","committed":false,"purpose":"helpers downloaded from /reference/cluster/scripts/"},{"path":"architect/","committed":false,"purpose":"cached visualizer"},{"path":".runtime/","committed":false,"purpose":"daemon ephemera"}],"gitignore_contract":[".meshkore/.runtime/",".meshkore/credentials/",".meshkore/agents/",".meshkore/timeline/",".meshkore/log/",".meshkore/queues/",".meshkore/uploads/",".meshkore/snapshots/",".meshkore/state.json",".meshkore/roadmap/state.json",".meshkore/roadmap/state.js",".meshkore/scripts/"],"gitignore_contract_note":"v27 deny-list: commit public/ + docs/ + modules/ + roadmap/initiatives/ + STANDARD_VERSION (the project's identity, instructions, plan and task history travel with the repo); gitignore runtime state, credentials, per-machine identity (agents/), timeline, daily logs, queues, uploads, snapshots, generated roadmap state, and downloaded scripts. Replaces the pre-v27 allowlist (.meshkore/* + !public/) that committed ONLY public/. `daemon.py init` writes exactly this block."},"cluster_yaml":{"required_fields":["version","id","type","name","transport.endpoint","modules"],"fields":{"version":{"type":"integer","literal":1},"id":{"type":"string","pattern":"^[a-z0-9-]{2,40}$"},"type":{"type":"string","enum":["dev","comms","service","mixed"]},"name":{"type":"string"},"description":{"type":"string","optional":true},"transport":{"type":"object","fields":{"workflow":{"type":"string","enum":["websocket","sse","nats"],"default":"websocket"},"endpoint":{"type":"string","format":"uri","required":true},"fallback":{"type":"string","format":"uri","optional":true}}},"bootstrap":{"type":"object","optional":true,"fields":{"hub":{"type":"string","format":"uri"},"install":{"type":"string","format":"uri"},"operate":{"type":"string","format":"uri"},"standard":{"type":"string","format":"uri"},"spec":{"type":"string","format":"uri"}}},"git":{"type":"object","optional":true,"fields":{"repo":{"type":"string"},"branch":{"type":"string","default":"main"},"auto_pull":{"type":"boolean","default":true},"auto_commit":{"type":"boolean","default":false}}},"architect":{"type":"object","fields":{"port":{"type":"integer","default":5570}}},"profile":{"type":"object","fields":{"capabilities":{"type":"array","items":"string","default":[]},"visible_in_directory":{"type":"boolean","default":false}}},"admission":{"type":"object","fields":{"mode":{"type":"string","enum":["pubkey","manual","open"],"default":"pubkey"},"approval":{"type":"string","enum":["auto","auto-on-github","manual"],"default":"manual"},"github_users":{"type":"array","items":"string"},"admission_token_lifetime":{"type":"integer","default":3600},"max_pending_requests":{"type":"integer","default":50}}},"members":{"type":"array","items":{"type":"object","required":["id","role","pubkey","pubkey_fingerprint","authorized_at","authorized_by"],"fields":{"id":{"type":"string"},"role":{"type":"string","enum":["coordinator","participant"]},"pubkey":{"type":"string"},"pubkey_fingerprint":{"type":"string","pattern":"^SHA256:"},"github_user":{"type":"string","optional":true},"authorized_at":{"type":"string","format":"date"},"authorized_by":{"type":"string"}}}},"modules":{"type":"array","min":1,"must_include_id":"general","items":{"type":"object","required":["id","kind"],"fields":{"id":{"type":"string","pattern":"^[a-z0-9-]{2,40}$"},"name":{"type":"string","optional":true},"kind":{"type":"string","enum":["code","spec","docs","area"]},"path":{"type":"string","optional":true},"parent":{"type":"string","optional":true},"description":{"type":"string","optional":true}}},"must_include_ids":["general","project"]},"snapshots":{"type":"object","optional":true,"description":"Pre-modification file snapshots config (Standard v19). When absent, daemon defaults to enabled + 7d retention.","fields":{"enabled":{"type":"boolean","default":true},"retention_days":{"type":"integer","min":1,"max":365,"default":7}}}}},"task_frontmatter":{"location_template":".meshkore/modules/<module-id>/tasks/<ID>-<slug>.md","required":["id","title","status","priority","owner","category","created","updated"],"fields":{"id":{"type":"string","pattern":"^[A-Z][A-Z0-9]{0,3}\\d+$"},"title":{"type":"string"},"status":{"type":"string","enum":["backlog","next","active","blocked","done","draft"],"description":"Task lifecycle state. Allowed: active, next, planned, in-progress, in_progress, doing, done, backlog, cancelled, pending-operator, blocked, draft. `draft` (Standard v15+) means the spec isn't finalised — neither Run-all nor per-initiative dispatch will run code against it. Operator owns the draft → next promotion."},"priority":{"type":"string","enum":["low","medium","high","critical"]},"owner":{"type":"string"},"category":{"type":"string","description":"MUST equal a declared module id from cluster.yaml"},"created":{"type":"string","format":"date"},"updated":{"type":"string","format":"date"},"tags":{"type":"array","items":"string","optional":true},"depends_on":{"type":"array","items":"string","optional":true},"initiative":{"type":"string","optional":true},"parent_initiative":{"type":"string","optional":true},"order":{"type":"integer","min":0,"max":9,"optional":true},"effort":{"type":"string","optional":true},"completed_at":{"type":"string","format":"date-time","optional":true,"description":"Standard v26+ — ISO timestamp written when an agent finishes the task (its turn emits chat.assistant.final and the task is `done`). Set by the daemon; a CLI agent setting status:done by hand SHOULD also set this."},"resolved_by":{"type":"string","optional":true,"description":"Standard v26+ — the agent (agent_id, else conv slug) that resolved the task."},"resolved_by_conv":{"type":"string","optional":true,"description":"Standard v26+ — the conversation whose final turn resolved the task. Links the task back to its execution history."},"commit_shas":{"type":"array","items":"string","optional":true,"description":"Standard v26+ — git commits associated with the task's resolution. Optional; may be filled by the daemon or by hand."}},"body_sections":{"description":"Standard v26+ — reserved markdown sections in the task body. The body is the rich, human/agent-readable record under the frontmatter.","sections":{"Resolution":"## Resolution — written when the task is done: the agent's Output-Contract summary of what was done (≤8 lines + optional <details>), associated images, and links. The daemon writes/overwrites this from the resolving turn's final message; agents may edit it. This is the durable per-task history the Architect IDE + any CLI consumer read back."}},"done_handling":"When status becomes 'done', the daemon stamps `completed_at` + `resolved_by` + `resolved_by_conv` on the frontmatter and writes the resolving turn's summary into the `## Resolution` body section. The file MAY later move from modules/<id>/tasks/ to modules/<id>/log/<YYYY-MM>/; all resolution data travels with it."},"workflows":{"location":".meshkore/workflows/","purpose":"Reusable, indexed multi-step runbooks. Cross-cutting work that touches multiple scopes (docs + code + commit + deploy). When the operator says `apply W<N>`, an agent executes the Steps section and files a run log.","identifier":"W<N> — letter-prefix-then-number, joining the cluster's existing T/V/D/C/N/AG family.","file_naming":"W<N>-<slug>.md, one workflow per file. Filename prefix MUST match the `id` field in frontmatter.","frontmatter":{"required":["id","title","scope","status","priority","owner","created","updated"],"fields":{"id":{"type":"string","pattern":"^P\\d+$"},"title":{"type":"string"},"scope":{"type":"string","enum":["cluster","project","module"]},"status":{"type":"string","enum":["draft","stable","deprecated"]},"priority":{"type":"string","enum":["low","medium","high","critical"]},"owner":{"type":"string"},"created":{"type":"string","format":"date"},"updated":{"type":"string","format":"date"},"tags":{"type":"array","items":"string","optional":true},"needs_inputs":{"type":"array","items":"string","optional":true}}},"body_sections":["Goal","When to apply","Inputs","Preconditions","Steps","Verification","Rollback","Related"],"run_log":{"location":".meshkore/workflows/log/<YYYY-MM>/W<N>-<YYYY-MM-DD>-<context>.md","frontmatter":{"required":["workflow","date","operator","agent","outcome"]}},"gitignore":"Commit the workflow files + INDEX.md; keep log/ local per machine.","endpoints":{"GET  /workflows":"no-auth, list (id, title, scope, status, updated, log_count)","GET  /workflows/<id>":"no-auth, raw markdown + parsed frontmatter","GET  /workflows/<id>/runs":"no-auth, recent run-log entries (latest 50)","WS broadcast":"workflows.updated on file change"}},"links_registry":{"location":".meshkore/public/links.yaml","purpose":"Source of truth for where each module runs locally, where it is deployed in production, and what version is live. Replaces ad-hoc links.md lists.","scope":"Optional file. Projects that deploy nothing may omit it. The daemon treats a missing file as { version: 1, modules: [] }.","schema":{"version":{"type":"integer","const":1},"modules":{"type":"array","items":{"id":{"type":"string","description":"MUST match cluster.yaml.modules[].id"},"local":{"type":"object","optional":true,"fields":{"url":{"type":"string","format":"uri"},"command":{"type":"string"},"health":{"type":"string","optional":true}}},"prod":{"type":"object","optional":true,"fields":{"url":{"type":"string","format":"uri"},"provider":{"type":"string","enum":["fly","cloudflare-pages","cloudflare-workers","vercel","render","self-hosted","other"]},"project":{"type":"string","description":"Provider-side project/app name"},"region":{"type":"string","optional":true},"deploy_command":{"type":"string","optional":true},"deployed_version":{"type":"string","optional":true},"deployed_sha":{"type":"string","optional":true},"deployed_at":{"type":"string","format":"date-time","optional":true},"deployed_by":{"type":"string","optional":true}}},"repo":{"type":"object","optional":true,"fields":{"branch":{"type":"string"},"head_sha":{"type":"string"},"version":{"type":"string","optional":true}}},"notes":{"type":"string","optional":true}}}},"maintenance":"Agent-maintained. Every commit that changes where a module runs, where it deploys, what branch it lives on, or what version it carries MUST update the matching entry in the same commit (extension of §6 commit conventions).","endpoints":{"GET  /links":"no-auth, full registry as JSON","GET  /links/<id>":"no-auth, one module's entry","POST /links/<id>":"bearer-auth, atomic patch of local/prod/repo blocks","WS broadcast":"links.updated on every rewrite"}},"doc_frontmatter":{"location_template":".meshkore/docs/<category>/<file>.md","required":["title","category","updated","owner","status"],"fields":{"title":{"type":"string"},"category":{"type":"string","enum":["architecture","product","conventions","deploy","security","ops","modules","governance"]},"tags":{"type":"array","items":"string","optional":true},"updated":{"type":"string","format":"date"},"owner":{"type":"string"},"status":{"type":"string","enum":["draft","stable","deprecated"]},"related":{"type":"array","items":"string","optional":true}},"exemptions":["INDEX.md (any folder)","README.md (any folder)",".meshkore/docs/governance.md",".meshkore/log/**",".meshkore/timeline/**","generated files: state.json, state.js, directory.json"]},"governance_rules":{"R1":{"title":"Categorize by intent, not by age","categories":{"architecture":"How is the system built?","product":"What are we, and why?","conventions":"What rules must I follow?","modules":"How does this specific code module work?","deploy":"How do I run / deploy this?","security":"What can go wrong?","ops":"What's happening day-to-day?"}},"R2":{"title":"Max 200 lines per file","split_when_over_lines":200},"R3":{"title":"One topic, one canonical file"},"R4":{"title":"Frontmatter required (see doc_frontmatter)"},"R5":{"title":"Link, don't copy"},"R6":{"title":"INDEX.md is a map, not content"}},"log_streams":{"session":{"path_template":".meshkore/log/<YYYY-MM-DD>.md","format":"human prose, append-only, topic-grouped","frontmatter":"not required (R4 exemption)","date_zone":"local"},"timeline":{"path_template":".meshkore/timeline/<YYYY-MM-DD>.jsonl","format":"one JSON event per line","generated_by":"daemon, build script, or .meshkore/scripts/timeline-append.py","date_zone":"UTC","event_shape":{"ts":"ISO-8601 UTC","type":"string (task.started | task.completed | task.failed | chat.user | chat.assistant.delta | chat.assistant.final | commit.created | deploy.completed | ...)","author":"member-id","text":"free-form"}},"debug":{"path":".meshkore/.runtime/debug.jsonl","convention":"https://meshkore.com/reference/conventions/debug-stream","feature_flag":"debug.stream.v1","daemon_min_version":"py-1.10.17","purpose":"Cross-component structured event stream the architect (or operator) tails to debug a session without screenshots. Daemon writes structured events directly; Architect IDE posts to POST /debug/log and the daemon stamps src='Architect IDE'.","retention":"30 minutes OR 5 MB, whichever ceiling hits first. Trim is atomic — keep events whose ts is within the last 30 min, rewrite the file.","gitignored":true,"event_shape":{"ts":"ISO-8601 UTC with ms (e.g. 2026-05-30T15:33:37.429Z) — required","src":"enum: daemon | Architect IDE | agent — required (server-forced to 'Architect IDE' for POST /debug/log)","lvl":"enum: debug | info | warn | error — required","tag":"kebab-case event category, dotted sub-namespaces allowed (e.g. architect-wake.skipped) — required","msg":"human-readable line, <= 4000 chars — required","conv":"conv id when conv-scoped — optional","agent_id":"Axx-style label — optional","data":"structured payload, token-like keys auto-redacted — optional"},"canonical_tags":["boot","log","chat-dispatch","subagent-final","architect-wake","architect-wake.skipped","architect-wake.failed","init-archive","http","ux.run-all","ux.stop-architect","ux.validation","transport.reconnect"],"redaction":{"keys_masked":["token","authorization","bearer","api_key","apikey","secret","password"],"value_pattern":"strings starting with 'Bearer ' longer than 24 chars are replaced with 'Bearer <redacted>'","applies_to":"data only; msg is not auto-scrubbed — producers must avoid embedding secrets in msg"},"endpoints":{"tail":{"method":"GET","path":"/debug/tail","auth":"Bearer <portal-token>","since":"py-1.10.17","query":{"last":"window in seconds, default 300","tag":"comma-separated tag filter, optional","level":"minimum level (debug < info < warn < error), default 'debug'"},"response_shape":{"events":"array of event objects, oldest first","retained_secs":"int — actual age of the oldest event still on disk","window_secs":"int — echo of the requested window","generated_at":"ISO-8601 UTC"}},"log":{"method":"POST","path":"/debug/log","auth":"Bearer <portal-token>","since":"py-1.10.17","body":"single event OR {events: [...]}","src_stamping":"server forces src='Architect IDE'; clients cannot forge src='daemon'","response_shape":{"accepted":"int — number of events persisted"}}},"feature_detect":{"endpoint":"GET /health","flag_path":"features.debug.stream.v1","absent_means":"daemon predates py-1.10.17 — Architect IDE MUST disable its POST /debug/log transport, log to console only, and show a quiet 'debug stream needs daemon >= py-1.10.17' banner. Tail endpoint absence MUST NOT raise."},"additivity":"Consumers MUST ignore unknown tags and unknown data fields rather than reject. New tags require a one-line note in the convention's canonical-tags table."}},"path_conventions":[{"writing":"A new task to track","path":".meshkore/modules/<module>/tasks/<ID>-<slug>.md"},{"writing":"A done task being archived","path":".meshkore/modules/<module>/log/<YYYY-MM>/<ID>-<slug>.md"},{"writing":"A cross-module initiative","path":".meshkore/roadmap/initiatives/<id>.md"},{"writing":"Per-module README","path":".meshkore/modules/<id>/README.md"},{"writing":"Architecture / product / convention doc","path":".meshkore/docs/<category>/<slug>.md"},{"writing":"Diagram","path":"<doc-slug>/diagrams/*.mmd (next to the doc it illustrates)"},{"writing":"Daily session log (prose)","path":".meshkore/log/<YYYY-MM-DD>.md"},{"writing":"Event timeline (machine)","path":".meshkore/timeline/<YYYY-MM-DD>.jsonl"},{"writing":"Cluster identity for the world","path":".meshkore/public/cluster.yaml"},{"writing":"Credentials / tokens / env vars","path":".meshkore/credentials/ (mode 0600, gitignored)"},{"writing":"Per-machine agent identity","path":".meshkore/agents/<id>.yaml"}],"hard_rules":["Never commit .meshkore/credentials/. Ever.","Never commit runtime/secret/per-machine state: .meshkore/{.runtime,credentials,agents,timeline,log,queues,uploads,snapshots,scripts}/, state.json, or roadmap/state.{json,js}. Everything else under .meshkore/ (public/, docs/, modules/, roadmap/initiatives/) IS committed since v27 (see folder_layout.gitignore_contract).","Never push to origin without the operator explicitly asking.","Never edit generated files (state.json, state.js, directory.json, .runtime/**).","Never invent a new top-level module / category without first declaring it in cluster.yaml.","Never duplicate normative content from this standard into a local doc. Link to https://meshkore.com/standard.","Every commit produced by an LLM agent must carry `Agent:`, `Model:`, and `MeshKore:` git trailers identifying the agent role, the model id, and the cluster's daemon version. Do NOT add `Co-Authored-By:` — git author already records the committer; the three semantic trailers fully attribute the AI. See `commit_attribution`.","Every chat mention of an initiative or task an agent is creating, modifying, deferring, splitting, or removing must include `#<id>` (the item's frontmatter id with a `#` prefix). Bare titles are not addressable in the Architect IDE UI. See `chat_id_references`.","Every agent turn must anchor to (initiative_id, task_id) before performing code work. Agents whose dispatch arrived without an anchor MUST locate or create the matching initiative + task as their first action, then continue. See `initiative_anchored_execution`.","Project context (.meshkore/context/) MUST be serialized into every agent briefing — the `=== PROJECT CONTEXT === … === END CONTEXT ===` block, before the agent-type role — per `context.serialization_to_agent`. A daemon that dispatches agents without it (or that injects only the legacy single-file docs/context.md) is non-conformant.","Never duplicate a context/ invariant into docs/. `context/` holds the canonical WHAT/invariants (loaded every spawn); `docs/<category>/` holds the categorized HOW (reference, on demand) and LINKS to context/ via wikilink. One fact, one home — no parallel docs/product|stack|architecture tree restating context/. See `context.relationship_to_docs`.","Never create, write, or run a per-project daemon. A member project has NO `.meshkore/scripts/daemon.py`, no `daemon.py`/`make`/`Makefile` daemon target, no version-poller, and never binds ports 5570-5589. ONE shared daemon per machine serves every project, routed by the `X-MeshKore-Project` header. 'Applying the standard' means the `.meshkore/` layout only — never standing up a daemon. See `daemon_topology` and `python_daemon`.","Never hand-write the `MESHKORE_PREAMBLE` block of `.meshkore/public/AGENT_INSTRUCTIONS.md` or the rendered `CLAUDE.md`/`AGENTS.md`/`GEMINI.md`/… — the daemon renders it verbatim from this standard (§17). Editing it by hand causes drift. Only the `OPERATOR_CONTENT` block below the preamble is operator-owned.","Never delete a `required: true` team member (architect-master, roadmap-orchestrator) and never run a second live instance of a singleton member. `.meshkore/team/` is committed — do NOT add it to the gitignore deny-list. Every team member MUST carry a `model`. See `agent_team`.","Never write a team member's bearer token into the committed member file (or any committed file) — it lives ONLY in `.meshkore/credentials/team-tokens.yaml`. Never expose the team ask/poll surface off-machine by port-forwarding the daemon: loopback binding is the v1 perimeter; cross-machine consumption is mesh exposure via identity, not an open port. See `agent_team.external_exposure`."],"editor_boot":{"filenames":{"claude":"CLAUDE.md","cursor":".cursorrules","windsurf":".windsurfrules"},"block_url":"https://meshkore.com/standard.md#8-editor-boot-block-canonical","block_text":"See section 8 of the canonical document; paste verbatim. Editor-specific extras go BELOW the canonical block, never above."},"python_daemon":{"url":"https://architect.meshkore.com/reference/cluster/scripts/daemon.py","implementation":"python","shared_service":true,"install_scope":"Once per machine, at the meshkore-server/ root. Member projects do NOT download or run it and carry no daemon code. Adopting a repo never means curling daemon.py into it.","min_python":"3.8","deps":"stdlib only (no pip, no venv)","platforms":["macos","linux","windows"],"rationale":"Drops cleanly onto enterprise machines that block unsigned binaries. The operator (or an AI agent, once) installs ONE shared daemon per machine; it serves every project.","endpoints":{"GET  /health":"no-auth, machine-level identity + default-project summary","GET  /info":"no-auth, machine-level /health + version + paths","GET  /projects":"no-auth, machine-level list of registered projects (id, name, path, default)","POST /projects":"bearer-auth, machine-level register a project by path (scaffolds + lazy-loads its ProjectContext)","DELETE /projects/<id>":"bearer-auth, machine-level unregister a project (its on-disk ledger is preserved)","GET  /state":"no-auth, PROJECT-scoped (requires X-MeshKore-Project) filesystem-derived state.json","GET  /reload":"bearer-auth, PROJECT-scoped rebuild + broadcast","GET  /agents":"no-auth, PROJECT-scoped list of .meshkore/agents/*.yaml","GET  /events":"WebSocket: hello, heartbeat, state.rebuilt (events tagged with project_id), daemon.shutdown","POST /shutdown":"bearer-auth, machine-level graceful exit (stops ALL projects at once; rare)"},"project_routing":"Every project-scoped request MUST carry header `X-MeshKore-Project: <cluster-id>`. Without it the daemon answers for its default (boot) project and a bare /health|/state may report a DIFFERENT cluster_id — that is EXPECTED, not 'wrong cluster' or 'daemon down'.","scope_today":"Single canonical L3 implementation for the whole machine — read paths (visualization, file-derived state, the /projects listing, lifecycle) plus runner surface (agent dispatch, chat, headless claude --session-id, cron scheduling), multiplexed across all registered projects by X-MeshKore-Project.","remove_project":"DELETE /projects/<id> drops one project (rail Remove button); the on-disk ledger is preserved. There is no per-project process to kill.","stop_from_architect":"POST /shutdown with the bearer token from the shared daemon's credentials stops the WHOLE machine daemon (all projects). Rare."},"adding_projects":{"human_url":"https://meshkore.com/standard#10-3-adding-a-project-to-your-architect","model":"Register the repo path with the already-running shared daemon. Never stand up a daemon.","modes":{"local":{"status":"available","summary":"In the Architect click '+ Add project' and point it at the repo path. The Architect calls POST /projects {path}; the shared daemon scaffolds .meshkore/ if missing, registers it in projects.json, lazy-loads a ProjectContext, and serves it via X-MeshKore-Project. Nothing new runs; no port is bound.","architect_button":"#projects-rail-add (opens modal in architect.meshkore.com)","prompt_url":"https://meshkore.com/standard#10-3-1-the-canonical-apply-standard-prompt","agent_role":"An AI agent MAY prepare the repo's .meshkore/ files, but MUST NOT download or run a daemon or bind a port. Its job ends at the files."},"cloud":{"status":"in-progress","summary":"Add a remote project (teammate's laptop, VM, or mobile) by registering a bridge with a cloud relay. Architect connects to the relay instead of localhost. Owned by a separate work-stream — see hand-off prompt.","transport_change":"architect -> cloud relay (WSS) -> bridge -> shared Python daemon (on remote machine)","daemon_contract_preserved":true,"out_of_scope_for_standard":["auth","billing","rate-limiting","bridge<->relay transport"]}}},"daemon_topology":{"model":"centralized","since":"v28 (2026-06-30); per-folder model retired 2026-06-25","initiative":"daemon-centralized","summary":"ONE shared daemon process per machine serves every project from a single base URL, routed by the X-MeshKore-Project header. Member projects carry no daemon code, bind no port, and run nothing.","one_per_machine":true,"port_range":[5570,5589],"default_port":5570,"port_ownership":"The shared daemon binds the first free port in 5570-5589 (written to its OWN .runtime/port). Member projects MUST NOT bind this range.","routing_header":"X-MeshKore-Project: <cluster-id> on every project-scoped request; machine-level routes (/health, /info, /projects) are unscoped.","discovery":"Architect lists projects via GET /projects (not a port scan) over one connection; switches project by changing the X-MeshKore-Project header.","isolation":"Each project's state/runs/chat/crons/credentials live in its own ProjectContext; a per-request try/except returns 500 for the failing project without affecting others.","global_ledger":"The shared daemon keeps its own machine-local (non-git) .meshkore/: ideas, projects.json (id->path), external-cluster credentials, external-agent config.","no_per_project_daemon":"Member projects have NO .meshkore/scripts/daemon.py. Do not create, git-checkout, download, or run one; do not add make/Makefile daemon targets. Doing so collides with the shared daemon on 5570-5589 (this broke an early v27 adopter)."},"validation":{"local_command":"python3 .meshkore/scripts/roadmap-build.py --validate","checks":["folder layout matches §2","public/cluster.yaml validates against §3","every task has category matching its module id","every task has required frontmatter fields","every non-exempt doc has required frontmatter fields",".gitignore contains the v27 deny-list contract from §2.2 (runtime/secret/per-machine state ignored; public/ + docs/ + modules/ + roadmap/initiatives/ committed)"],"ci_hook":"roadmap-build.py --validate; daemon runs it on boot; architect shows yellow warnings for invalid files","schema_checks":["cluster.yaml.modules MUST include both `general` and `project` (the meta bucket). Older clusters that predate v12.1 should run the v12.1 catch-up before any new tasks are dispatched."]},"versioning":{"current":"6.0.0","semver":{"major":"breaking change to folder layout, schemas, or hard rules","minor":"new section, new optional field, new path convention","patch":"clarifications, wording, examples"},"changelog_url":"https://meshkore.com/standard#11-versioning","migration_signal":"On major bump, the daemon polls /standard/version and refuses cluster writes until the operator updates .meshkore/STANDARD_VERSION (after applying the manual migration block from CHANGELOG.md)."},"layer_model":{"L0":{"label":"folder","needs_account":false,"needs_binary":false,"needs_network":false,"scope":"this standard"},"L1":{"label":"rules","needs_account":false,"needs_binary":false,"needs_network":false,"scope":"this standard + editor boot block"},"L2":{"label":"hub","needs_account":true,"needs_binary":false,"needs_network":true,"scope":"discoverability"},"L3":{"label":"daemon","needs_account":false,"needs_binary":false,"needs_network":"localhost","scope":"local automation"},"L4":{"label":"mesh","needs_account":true,"needs_binary":false,"needs_network":true,"scope":"cross-cluster agent calls"}},"agent_protocol":{"fetch_at_session_start":"https://meshkore.com/standard/version","fetch_full_schema":"https://meshkore.com/standard.json","fetch_changelog_on_drift":"https://meshkore.com/standard/CHANGELOG.md","cache_ttl_seconds":86400,"before_writing_code":"Fetch the relevant standards/stack/<layer>.md and standards/audit/<stack>.md from /reference/standards/.","on_drift":"If a local doc contradicts this standard, surface diff to the operator and ask before overriding. This standard is canonical for universal pieces; project-specific overrides must be marked as such."},"commit_attribution":{"applies_to":"Every git commit whose author or co-author is an LLM agent (Claude or otherwise) in any MeshKore repo. Human-only commits MAY omit; mixed-authored commits MUST include. The operator's general convention across non-MeshKore repos is the opposite (no co-authoring trailers at all) — MeshKore is the explicit exception because git history of agent-driven work needs to be auditable per-role + per-model + per-cluster-version.","format":"Git trailers appended to the commit message body, after a blank line at the end. The three semantic trailers below are MANDATORY in this order. The legacy `Co-Authored-By:` trailer is REMOVED as of v21 (git's author/committer field already records who ran the commit; the three semantic trailers fully attribute the AI).","trailers":{"Agent":{"required":true,"description":"The agent ROLE / type that produced the commit. Comes from the daemon's `agent_type` field or the conv slug pattern.","examples":["master","roadmap-architect","work-I13-CAT2","deploy-cavioca-prod","review","docs","custom"]},"Model":{"required":true,"description":"The exact MODEL ID the agent ran under, as published by the model vendor. Use `Model: unknown` if the runner truly doesn't know — never omit silently.","examples":["claude-opus-4-8","claude-opus-4-7","claude-sonnet-4-6","claude-haiku-4-5","gpt-5","cursor-default"]},"MeshKore":{"required":true,"description":"The MeshKore DAEMON version this cluster was running when the commit was authored (the agent's effective MeshKore runtime). Quote the literal `py-X.Y.Z` from the daemon's `DAEMON_VERSION` constant — the daemon embeds it in every subagent briefing so the value is always known at commit time. Lets `git log` filter the cohort of commits produced under a given daemon version: useful for tracing regressions back to a specific runtime, and for measuring how a new daemon feature ripples through real work.","examples":["py-1.12.15","py-1.12.14","py-1.11.2","py-1.10.13"]},"Standard":{"required":false,"description":"Only on commits that bump the MeshKore standard itself (the four files at webapp/standard.{md,json}, standard/CHANGELOG.md, standard/version). Format: `Standard: vN-1 → vN`. Pair with `Section:` naming the top-level key changed.","example":"Standard: v20 → v21"},"Section":{"required":false,"description":"Companion to `Standard:` — names the top-level key in standard.json that received the change. Helps the standard-evolution diary stay greppable.","example":"Section: commit_attribution"}},"removed_trailers":{"Co-Authored-By":"REMOVED in v21. Was a pre-existing convention from the Claude Code CLI default. Adds no information that Agent + Model + git's own author/committer fields don't already carry, and the operator's cross-repo convention is no-co-authoring. Do NOT add this trailer to MeshKore commits."},"example":"feat(rail): show waiting-on pill while subagents stream\n\nMaster polled its waiting list every 2s — replaced with WS-driven\nincrementals so the pill flips the moment a child finalises.\n\nAgent: master\nModel: claude-opus-4-7\nMeshKore: py-1.12.15","example_with_standard_bump":"feat(standard): v20 → v21 — add MeshKore daemon-version trailer, drop Co-Authored-By\n\n<why this change>\n\nAgent: master\nModel: claude-opus-4-7\nMeshKore: py-1.12.15\nStandard: v20 → v21\nSection: commit_attribution","rationale":"Field-reported 2026-06-02: a fast 'resync' pass from a roadmap-architect looked indistinguishable in git history from real subagent work. Trailers make the role / model / runtime legible to git log / blame / analytics, enable cohort metrics across versions, survive merges + cherry-picks unchanged, and — with the v21 `MeshKore:` addition — let operators correlate commit activity with specific daemon releases (e.g. 'all the broken markdown-rendering commits clustered under py-1.12.13 because of <bug>; py-1.12.14 fixed it').","parsing":"`git interpret-trailers --parse` extracts these as RFC 5322 headers. Analytics example: `git log --format='%H%n%(trailers:key=Agent,valueonly,separator=)%n%(trailers:key=Model,valueonly,separator=)%n%(trailers:key=MeshKore,valueonly,separator=)'`.","non_llm":"Human-only commits MAY omit Agent + Model trailers. A commit by an agent that DOESN'T know its model id (rare; usually a misconfigured runner) MUST set `Model: unknown` — never omit silently.","applies_to_subagents":"The daemon spawns subagents via Claude Code; the agent's spawn-time briefing now includes its own `Agent:` slug and `Model:` id, so each subagent stamps its own commits correctly without operator intervention."},"project_bucket":{"applies_to":"Every cluster created at standard v12.1+. Older clusters may lack it and need a one-time migration (see CHANGELOG v12.1).","what":"A meta module with `id: project, kind: area, no parent` that sits as the conceptual root for cross-cutting work that doesn't belong to a single code folder.","minimum_children":[{"id":"deploy","name":"Deploy","kind":"area","parent":"project","purpose":"CI/CD, deploy scripts, runbooks, env config, cloud provider setup."},{"id":"docs","name":"Docs","kind":"area","parent":"project","purpose":"READMEs, architecture notes, operator manuals, narrative docs (not auto-generated reference)."},{"id":"design","name":"Design","kind":"area","parent":"project","purpose":"Visual tokens, brand, design system, UI patterns shared across surfaces."},{"id":"general","name":"General","kind":"area","parent":"project","purpose":"Catch-all for project-wide work that doesn't belong to a single module yet."}],"growable":"More area children (audit, security, infra, launch, seo, payments, marketplace, ecosystem, future, ...) declared on demand as the project earns them. Never seeded ahead of work.","code_module_peers":"Real source code modules (web, api, daemon, worker, sdk, ...) sit as PEERS of `project`, not as children. They carry `kind: code` + `path: <folder>` and own a real source tree.","rationale":"Without this bucket, cross-cutting work (deploy, design, audit) lands mixed with code modules and the operator can't tell at a glance which items ship code vs which are organizational. The bucket also gives the Architect IDE's Context tab a stable place to render project-level docs (`.meshkore/modules/project/README.md` + child READMEs).","playbook":"https://meshkore.com/reference/prompts/roadmap-author/v1/cluster-modules.md","canonical_example":"https://github.com/meshkore/meshkore (.meshkore/public/cluster.yaml)"},"module_readme":{"applies_to":"Every module declared in cluster.yaml.modules MUST have a README.md at `.meshkore/modules/<id>/README.md`. The Architect IDE's Context tab renders this file verbatim when the operator selects a module.","path":".meshkore/modules/<id>/README.md","frontmatter":{"required":["title","category","updated","status"],"fields":{"title":{"type":"string","description":"Display name. Must match cluster.yaml.modules[<id>].name."},"category":{"type":"string","const":"modules","description":"Always literal 'modules' — keeps the Architect IDE's doc index consistent."},"tags":{"type":"array","items":{"type":"string"},"optional":true},"updated":{"type":"string","format":"date","description":"ISO date YYYY-MM-DD. Bumped on every substantive edit."},"owner":{"type":"string","optional":true,"description":"Operator handle / agent slug responsible for keeping this current."},"status":{"type":"string","enum":["stub","draft","stable"],"description":"stub = generated, content placeholder. draft = has real content but evolving. stable = the module's core surface is stable and the README reflects it."},"related":{"type":"array","items":{"type":"string"},"optional":true,"description":"Other module ids that frequently appear in the same workflow."}}},"body":{"max_lines":150,"sections":[{"name":"Purpose","required":true,"shape":"1-2 lines describing what this module is responsible for in operator-readable language."},{"name":"Code","required_if":"kind == 'code'","shape":"Path to the source folder (e.g. `apps/web/`). Omit for `area` / `spec` / `docs` kinds."},{"name":"Surface","required":true,"shape":"2-4 lines or 3-6 bullets listing what this module EXPOSES — URLs, CLI commands, file paths, public functions. Contact points only, no deep dive."},{"name":"Out of scope","required":false,"shape":"1-2 bullets clarifying things operators might expect to find here but live elsewhere."}]},"lifecycle":{"create":"Roadmap Author generates a stub during cluster bootstrap (status=stub).","update":"Sub-agents (`custom` / `deploy` / `db` / `testing` / `docs`) update the relevant README every commit that changes the module's externally-visible surface. Bumps `updated:` to current ISO date, raises `status:` (`stub` -> `draft` on first real commit, `draft` -> `stable` when surface is settled).","verify":"Roadmap Architect spot-checks on initiative close that touched modules have READMEs reflecting what shipped."},"anti_patterns":["Empty README.md — equivalent to no documentation; CONTEXT tab renders blank.","README.md exceeding 150 lines — split into sub-files under `.meshkore/modules/<id>/` instead of bloating one file.","Missing frontmatter — the Architect IDE's doc index can't categorize the file; it falls out of the navigation.","Status stuck at `stub` after the module has shipped real code — bump to `draft` or `stable` so the operator knows where they stand."],"playbook":"https://meshkore.com/reference/prompts/roadmap-author/v1/module-readmes.md"},"cross_references":{"since":"v25","syntax":"[[<path-relative-to-.meshkore>]]","resolution":"Resolved relative to .meshkore/; the .md extension is implied. Examples: [[context/decisions/2026-06-08-chat-turn-queue]], [[docs/deploy/architect]], [[modules/<id>/tasks/<task>]].","rationale":"Survives renames better than [text](path.md); lingua franca of Obsidian/Logseq/Foam. Use for see-also references between .meshkore files; keep standard markdown links for external URLs.","lint":"Daemon MAY lint broken wikilinks as a non-blocking warning on its file-poll cycle. Not yet enforced; advisory in v25."},"context":{"purpose":"Project-wide INVARIANT knowledge loaded into every agent spawn. NOT task state, NOT runtime data, NOT credentials, NOT audit procedure. Theory-grounded in agent context engineering (Anthropic, Cline memory-bank, Cursor .cursorrules): every token costs reasoning bandwidth, so only include what changes an agent's decision and would otherwise be re-debated.","folder":".meshkore/context/","committed":"public/cluster.yaml mentions context; the context folder itself stays local-only by default (.meshkore/* gitignore rule). Optional opt-in via cluster.yaml.context.commit: true if the operator wants context to travel with the repo.","relationship_to_docs":"context/ = single source of truth for INVARIANTS (the WHAT, loaded into every spawn). docs/<category>/ = categorized reference for the HOW (detail, consulted on demand). docs/ LINKS to context/ via wikilink and NEVER copies an invariant. High-level stack -> context/stack.md; deploy/ops detail -> docs/deploy/ + docs/ops/. There is no docs/stack/ category. Anti-pattern: a parallel docs/product|stack|architecture tree that re-states context/ (duplicates the source of truth and drifts). One fact, one home.","canonical_tree":{"overview.md":{"required":true,"max_words":200,"purpose":"WHAT this project is, scope, status. 1 short paragraph."},"product.md":{"required":true,"max_words":200,"purpose":"WHO uses it, value, anti-product (what it explicitly is NOT)."},"stack.md":{"required":true,"max_words":200,"purpose":"Blindado tech decisions. Markdown table preferred. Forbidden swaps listed."},"architecture.md":{"required":true,"max_words":250,"purpose":"Mental model: layers, ownership, data flow. Diagrams OK (ASCII or mermaid)."},"constraints.md":{"required":true,"max_words":250,"purpose":"Hard rules — never-do / always-do. Security + architectural. Bullet list."},"glossary.md":{"required":false,"max_words":250,"purpose":"Domain terms → 1-line definitions. Table form. Only terms the agent would otherwise misuse."},"decisions/":{"required":true,"growable":true,"purpose":"ADR-style log. Each file ≤100 words: context → decision → consequences."},"decisions/README.md":{"required":true,"purpose":"INDEX of decisions, newest first. Table: date + slug + 1-line."},"decisions/YYYY-MM-DD-<slug>.md":{"naming":"YYYY-MM-DD-<kebab-slug>.md","max_words":100},"criteria/":{"required":false,"growable":true,"purpose":"When-X-vs-Y rules. Each file ≤100 words."},"criteria/<slug>.md":{"naming":"<kebab-slug>.md","max_words":100}},"brevity_contract":{"total_budget_words":3000,"total_budget_tokens_approx":4500,"rationale":"Loaded into every agent spawn. Larger budgets bleed reasoning bandwidth + cost.","enforcement":"Daemon emits context_tree.token_estimate in /state. Architect IDE shows a budget badge. Architect dispatch refuses to launch when over budget (it summarizes + flags `context: over-budget` in the next end-of-pass)."},"frontmatter":{"required":["title","updated"],"fields":{"title":{"type":"string","max_chars":60},"updated":{"type":"string","format":"date"},"status":{"type":"string","enum":["stub","draft","stable"],"optional":true}},"kill_list":"No tags, no owner, no related — context frontmatter is intentionally minimal. Add them to docs/* if needed; not here."},"serialization_to_agent":{"when":"On every subagent spawn (daemon-side, in ChatRunner.brief()).","order":["=== PROJECT CONTEXT ===  → overview.md","=== PRODUCT ===          → product.md","=== STACK ===            → stack.md","=== ARCHITECTURE ===     → architecture.md","=== CONSTRAINTS ===      → constraints.md","=== GLOSSARY ===         → glossary.md (skipped if missing)","=== DECISIONS (newest first) === → decisions/*.md, sorted by date desc","=== CRITERIA ===         → criteria/*.md, alphabetical by slug (skipped if missing)"],"position_in_briefing":"BEFORE the agent-type role block. Stable across all agent types. Cached by daemon, refetched only on file mtime change.","footer_marker":"=== END CONTEXT ===  — agents are instructed to treat everything above this marker as invariant."},"scope_exclusions":["Audit procedure → lives in `.meshkore/workflows/` (operator-defined frequency, runbook).","Credentials → lives in `.meshkore/credentials/` (gitignored) + `.meshkore/credentials.age` (sealed, optional).","Bookmarks, crons, links, logs, config — each has its own `.meshkore/<storage>/`.","Roadmap state (initiatives, tasks, status) → `.meshkore/roadmap/` + `.meshkore/modules/<id>/tasks/`. Volatile, not context.","Module READMEs → `.meshkore/modules/<id>/README.md`. Per-module surface, not project-wide invariant."],"write_rules":{"default":"Skip. Most work does not warrant a context write.","write_when":["Establishes a new invariant other agents would re-debate (stack swap, security rule, cross-cutting pattern).","A decision with a non-obvious rationale (ADR-worthy → decisions/).","A criterion / threshold (when X vs Y → criteria/).","A domain term easy to misuse → glossary update."],"skip_when":["It's task state (lives in roadmap).","It's audit/workflow procedure.","It's secret access.","It's narrative documentation for humans (lives in `.meshkore/docs/`)."],"actor_responsibilities":{"Roadmap Author":"Bootstraps overview/product/stack/architecture/constraints/glossary on cluster generation. Stubs decisions/ + criteria/ indexes.","Master Architect":"Maintains overview + stack + architecture + constraints. Appends decisions/ + criteria/ entries as operator dialogue produces them.","Sub-agents (custom/deploy/db/testing/audit/docs/review)":"Default: skip. Append to decisions/ or criteria/ ONLY when work crystallizes a new project-wide invariant. Bump `updated:` of touched files."}},"anti_patterns":["Essay paragraphs — context is bullets/tables/code-blocks, not prose.","Marketing copy — context is internal, agent-targeted; no taglines.","Duplicating module READMEs into context — module READMEs serve the Modules panel; context serves spawn-briefing. Different audiences.","Volatile state in context — task progress, sprint goals, last-deployed-sha belong in roadmap/logs.","Frontmatter bloat — only `title` + `updated` (+ optional `status`)."],"playbook":"https://meshkore.com/reference/prompts/roadmap-author/v1/context-bootstrap.md"},"task_status":{"dispatchable":["active","next","planned","in-progress","in_progress","doing"],"terminal":["done","cancelled"],"blocked":["blocked","pending-operator","pending_operator"],"parked":["backlog"],"draft":["draft"],"rules":{"run_all_skips":["draft","done","cancelled","backlog"],"per_initiative_skips":["draft","done","cancelled","backlog"],"auto_promote_forbidden":"Architect MUST NOT auto-promote `draft` → `next`. Operator-only transition.","initiative_completion":"Initiative `status: done` requires EVERY child task in `done`. Tasks in `draft|active|next|blocked|in_progress|backlog` keep the initiative `active`.","rationale":"Draft = spec under authorship, not under execution. Promote on intent, not on availability."}},"chat_queue":{"purpose":"Per-conv FIFO of operator-authored prompts that wait their turn. Auto-flushes when the conv goes idle after a turn final. Enables operators to queue several follow-up instructions while a long-running task is still in flight.","storage":".meshkore/queues/<conv>.json — committed: false. Created on first enqueue; deleted when empty (no archeology after the last item dispatches).","file_shape":{"conv":"<conv-slug>","version":1,"items":[{"id":"qt_<10hex>","text":"<prompt body>","created_at":"<ISO>","position":"<0..N-1>","status":"queued | sending | sent | failed | cancelled","sent_at":"<ISO?>","failed_reason":"<string?>"}]},"limits":{"max_items_per_queue":50,"max_text_bytes":64000},"http_routes":{"GET /chat/conv/<conv>/queue":"list — returns { conv, version, items: [...] }","POST /chat/conv/<conv>/queue":"enqueue — body { text }; returns the new item","POST /chat/conv/<conv>/queue/<id>/edit":"edit — body { text }; 409 if item already dispatched","POST /chat/conv/<conv>/queue/<id>/move":"reorder — body { position }; 409 if dispatched","POST /chat/conv/<conv>/queue/<id>/promote":"force-dispatch this item now (skip head)","DELETE /chat/conv/<conv>/queue/<id>":"remove"},"ws_events":["queue.item.added — body: { conv, item, ts }","queue.item.updated — body: { conv, item, ts } (edit OR move)","queue.item.removed — body: { conv, item, ts }","queue.item.sent — body: { conv, item, ts } (auto-flush handed off to /chat/dispatch)"],"auto_flush":"When `chat.assistant.final` fires AND the conv summary's `live=false coordinating=false`, the daemon pops the queue head and dispatches it as a normal user message via /chat/dispatch. If the head's status is not `queued`, the flush is a no-op (e.g. operator manually promoted via /promote).","rationale":"Pre-v16 operators had no way to queue further instructions while an agent was still working — they'd either wait, lose context, or fire-and-forget (interrupting the current turn). The queue lets operators script a small sequence of follow-ups without sitting on the prompt.","future_view":"A multi-agent column view (planned) reads `state.queues[conv]` for each agent and renders the queue as a checklist next to the agent's column. Same daemon contract — no extra storage.","scope_exclusions":["Not used by the architect or sub-agents to dispatch THEIR own work — that goes through /chat/dispatch directly.","Not persisted across cluster swaps (the queue belongs to one project's daemon).","Not exposed in the roadmap (queue items are chat-thread artifacts, not initiatives)."],"anti_patterns":["Treating the queue as a substitute for tasks/initiatives — it isn't; it's transient.","Auto-promoting all items in one round when the conv goes idle — only the HEAD pops per flush, by design (one turn = one item).","Skipping the dispatch hand-off and writing directly to convMap — every queued message must flow through /chat/dispatch for the daemon's normal lifecycle (timeline append, parent-wake, etc)."],"playbook":"https://meshkore.com/architect#queue"},"network_resources":{"introduced":"v17 (2026-06-09)","purpose":"Every cluster ships .meshkore/public/RESOURCES.md, a verbatim local mirror of https://meshkore.com/standard/resources.md. The file is a one-screen reference for the network's primary entry points (Oracle, hub directory, agent address scheme, deploy playbook, daemon upgrade flow) so any AI agent reading the project context immediately knows what the mesh offers and where to look.","rationale":"Before v17 the mesh worked but discoverability of the mesh itself inside a project was poor. Operators were re-explaining the same URLs in every prompt. A small predictable file at a predictable path closes the gap.","contract":{"path":".meshkore/public/RESOURCES.md","committed":true,"canonical_source":"https://meshkore.com/standard/resources.md","format":"markdown, one-screen, table + flows, stable schema","refresh":"the daemon, when it observes that local STANDARD_VERSION is older than https://meshkore.com/standard/version, fetches the canonical resources.md and overwrites the local copy up to the <!-- /canonical --> marker. Piggybacks on the existing standard-upgrade flow (§11)."},"operator_extensions":"Operators MAY append project-specific resources BELOW the <!-- /canonical --> marker. Content below the marker survives standard refreshes; content above is overwritten on bump.","agent_context_expectation":"Every system prompt template that a MeshKore-aware tool (daemon, Architect, OpenClaw skill, partner integrations) sends to a subagent SHOULD include a one-line awareness pointer such as: 'MeshKore network resources at .meshkore/public/RESOURCES.md — Oracle, hub directory, agent-use patterns, daemon upgrade flow.' The exact wording is up to the prompt template; what's mandated is that the agent be told the file exists.","what_it_does_not_contain":["Live state (online flags, agent counts). Queried fresh from the hub.","Project-specific URLs by default. Canonical block is network-level only.","Secrets or private endpoints. The file is public/, treat as world-readable."],"verification":"diff <(curl -s https://meshkore.com/standard/resources.md) <(sed -n '/^<!--$/q;p' .meshkore/public/RESOURCES.md | head -n -1)  # empty up to the marker"},"agent_instructions":{"introduced":"v18 (2026-06-09)","purpose":"Single canonical source of local-agent CLI instructions, rendered by the daemon into CLAUDE.md / AGENTS.md / GEMINI.md / etc. at the repository root. One file the operator edits → every supported AI assistant CLI sees the same instructions, with a MeshKore-savvy preamble (RESOURCES.md pointer, conventions, commit attribution) prepended by the standard.","rationale":"Each AI agent CLI looks at a different file for project rules (CLAUDE.md, AGENTS.md, GEMINI.md, .cursor/rules, ...). Without coordination the operator drifts. The standard fixes this by anchoring one source and letting the daemon fan out.","source":{"path":".meshkore/public/AGENT_INSTRUCTIONS.md","committed":true,"regions":["<!-- MESHKORE_PREAMBLE_BEGIN --> ... <!-- MESHKORE_PREAMBLE_END -->: managed by the daemon, overwritten on refresh.","<!-- OPERATOR_CONTENT_BEGIN --> ... <!-- OPERATOR_CONTENT_END -->: operator-owned, preserved across refreshes."],"canonical_preamble":"https://meshkore.com/standard/agent-instructions.md"},"render_targets":{"mandated_v18":["CLAUDE.md","AGENTS.md","GEMINI.md"],"optional_v18_mandated_v19":[".cursor/rules/meshkore.mdc",".clinerules"]},"refresh_triggers":["Standard version bump (STANDARD_VERSION < canonical online).","Operator edits AGENT_INSTRUCTIONS.md (file-mtime watch)."],"preamble_must_include":["Pointer to .meshkore/public/RESOURCES.md","Pointer to the canonical standard URL","Folder-layout invariants (public/ committed, modules/<m>/tasks/, log/)","Commit attribution rule (§9.1)","Standard-evolution workflow pointer","Mention of mesh primitives (Oracle, hub directory, /agent/<id> URL)","Initiative-anchored execution rule (§24) — locate-or-create (initiative, task) as the first action of an unanchored turn (v24)","Pointers to the cluster's standing context (§3.5 .meshkore/context/ incl. criteria/) and reusable runbooks (§14 .meshkore/workflows/) (v24)"],"verification":"Source has both markers; each rendered target matches source byte-for-byte except for the leading auto-render comment."},"snapshots":{"purpose":"Pre-modification copies of files an agent is about to touch. Operator-readable, agent-creatable, retention-bounded. NOT a git replacement — git owns merged history; snapshots own intermediate states between commits so the operator can inspect (and selectively restore via the agent) any moment between two commits without needing 20 micro-commits.","storage":".meshkore/snapshots/<YYYY-MM-DD>/<bucket-id>/ (gitignored; created lazily; retention-bounded)","bucket_id_format":"<YYYYMMDD>-<HHMMSSmmm>-<idHint>-<descSlug>-<4hex>  (lexicographic = chronological; idHint is agent_id || initiative_id || task_id || 'X'; descSlug derived from `note` or `task_id`)","layout":{"<bucket>/_manifest.json":"JSON: { id, date, created_at, conv, agent_id, agent_type, initiative_id, task_id, msg_id, note, files: [{ path, size, sha256, skipped? }], warnings }","<bucket>/files/<repo-relative-path>":"verbatim copy of the source file at snapshot time"},"http_routes":{"POST /snapshots":"create — body { paths: string[], conv?, agent_id?, agent_type?, initiative_id?, task_id?, msg_id?, note? }","GET /snapshots?limit=N":"list buckets newest-first (default 200, max 1000)","GET /snapshots/<bucket>":"manifest","GET /snapshots/<bucket>/files/<repo-relative-path>":"raw file body","DELETE /snapshots/<bucket>":"operator-driven cleanup"},"ws_events":["snapshot.created — { id, conv, agent_id, files }","snapshot.removed — { id }"],"config":{"cluster.yaml#snapshots.enabled":"bool, default true","cluster.yaml#snapshots.retention_days":"int 1-365, default 7"},"limits":{"max_files_per_bucket":50,"max_file_bytes":5000000},"gc":"Opportunistic on every snapshot.create — sweeps date directories older than retention_days. No separate cron; the write path keeps the tree bounded by definition.","agent_contract":"Before any tool call that Writes/Edits an EXISTING file, the agent MUST POST /snapshots with the list of paths it's about to modify. Skip for newly-created files (no prior content). The daemon copies + writes a manifest + appends to the daily log + broadcasts `snapshot.created`. This is non-negotiable per Standard v19 — agents not honoring it can't be diffed against intermediate states.","daily_log_integration":"On every snapshot.create the daemon appends to `.meshkore/log/<YYYY-MM-DD>.md`: `## <HH:MM:SS> · snapshot <id>` + agent line + file list + restore hint. Operators reading the diary see the file-change trail interleaved with prose events.","scope_exclusions":["NOT a versioned filesystem — retention drops old buckets.","NOT a git replacement — commits remain the source of truth for merged history.","NOT a transaction log — captures the BEFORE state, not the after; the agent's write produces the AFTER, and git captures the merged result.","NOT exposed to non-authenticated peers — all routes require the cluster's portal-token."],"future_ui":"V108+ Architect IDE will render the snapshot list inline in: (a) each chat message that triggered modifications, (b) each task card in the roadmap, (c) each daily-log entry. Operators will be able to diff snapshots against the working tree or against later snapshots without leaving the Architect IDE. Out of scope for v19 (storage-first).","playbook":"https://meshkore.com/standard#20-file-snapshots-v19"},"chat_id_references":{"purpose":"Make every chat mention of a roadmap item (initiative or task) machine-locatable and operator-clickable in the Architect IDE. Without this rule, agents describe roadmap mutations in prose (\"split the voting initiative into two\") and the operator has to grep file names to find what changed.","rule":"When an agent's chat output adds, removes, renames, defers, splits, blocks, or otherwise touches an initiative or a task, every mention of that item in the same line MUST include `#<id>` where `<id>` is the item's frontmatter `id:`. The `#` prefix is non-negotiable — the Architect IDE chat renderer turns `#<id>` into a clickable chip.","id_shape":{"regex":"^#[A-Za-z][A-Za-z0-9_-]{1,31}$","examples_initiative":["#I18","#I21","#PAYMENTS","#switchboard-cross-user"],"examples_task":["#T-vote-API","#WORK-21","#T-spiral-prefetch"]},"canonical_chat_lines":["✓ added #I18 task #T-vote-anon-toggle","✗ removed #T-fixture-loader from #I19 (folded into #T-spiral-prefetch)","↻ split #I21 into #I21 (chain) + #I27 (storage)","🔧 #I12 DEMO2 stub (AMOY_PRIVATE_KEY unset → testnet fixture)","✓ #I18 done (6/6 shipped). → #I19."],"exclusions":["Planning-aloud prose where no item is yet decided (\"we could do something about live-vote pulses…\") — bare prose is fine here.","Brand-new id introduced in the SAME line (\"+ #I27 (chain & storage refresh)\") — the create-line owns the id.","Operator-facing narrative paragraphs that aren't acting on items — long-form discussion can use titles freely as long as load-bearing mentions (the ones an operator would click) carry the `#<id>`."],"enforcement":"Lives in the universal-rules block of every agent's briefing (`daemon._section_core_rules()`). No automated linter yet; if drift becomes a pattern, add a regex check on outbound chat lines. Convention doc: `.meshkore/docs/conventions/chat-id-references.md`.","ui_integration":"The Architect IDE's V108 timeline (architect/) renders a `#<id>` chip at the head of each initiative's title row. Operators pattern-match by sight: chat says `#I21 split` → they look at the timeline, see the `#I21` chip glowing amber, and confirm two children now hang off it.","playbook":"https://meshkore.com/standard#22-chat-id-references-v20"},"storage_reporting":{"purpose":"Operator-visible disk-usage breakdown of `.meshkore/`. The Architect IDE renders a Storage panel showing per-bucket bytes + file counts + each bucket's retention policy, so the operator can spot runaway growth, tune retention, and trigger purges. Out of scope: data export, content viewing — this endpoint reports SIZES, not contents.","http_route":"GET /storage/usage","auth":"no auth required (metadata only, no contents)","cache":"server-side, 5s TTL — polling at 1Hz is safe, recomputing rglobs on every poll is not","response_shape":{"root":"string — always `.meshkore/`","total_bytes":"int","total_files":"int","buckets":"array of {name, bytes, files, exists, retention_days?}","generated_at":"ISO8601 UTC","cache_ttl_secs":"float — operator can use this to set their poll cadence"},"buckets":{"log":"daily activity logs (`.meshkore/log/<YYYY-MM-DD>.md`). No automated retention — operator culls manually.","snapshots":"Standard v19 file snapshots (`.meshkore/snapshots/<YYYY-MM-DD>/<bucket>/`). Retention: `cluster.yaml.snapshots.retention_days` (default 7).","uploads":"Standard v22 chat attachments (`.meshkore/uploads/<YYYY-MM-DD>/<file>`). Retention: `cluster.yaml.uploads.retention_days` (default 30).","queues":"Standard v16 chat-turn queues (`.meshkore/queues/<conv>.json`). No automated retention — items disappear when flushed.","timeline":"WS-replay event timeline. No automated retention; the daemon rotates by day.","agents":"declared agents + per-type memory.","modules":"module folders + per-task markdown — committed.","docs":"internal documentation + convention playbooks — committed.","roadmap":"initiatives + state.json — committed.",".runtime":"ephemeral per-machine state (pid, port, daemon.log, debug.jsonl).","credentials":"API keys, tokens — gitignored, never reported to remote sinks."},"retention_extensibility":"When a future feature adds a new bucket with its own retention, add the bucket to `StorageReport._BUCKETS` and the `_retention_for` map. The Architect IDE auto-renders unknown buckets without further changes.","playbook":"https://meshkore.com/standard#23-storage-reporting-v22"},"initiative_anchored_execution":{"purpose":"The roadmap is the project's guide. Every agent turn should be anchored to (initiative, task); the Architect IDE's roadmap timeline is then a live picture of what is happening across all concurrent agents. Without anchoring, agent work leaves no trace in the roadmap, can't be cross-referenced from the daily log, and breaks the Architect IDE's mental model.","rule":"Every agent's first action on a turn that lacks `conv_meta.initiative_id` + `task_id` is to LOCATE or CREATE the matching initiative + task. Code edits, deploys, and file mutations only happen AFTER the anchor is set.","decision_chain":["1. ANCHOR-PRESENT — both ids are set: acknowledge `→ working on #<init> · #<task>` and continue.","2. INITIATIVE-PRESENT, TASK-MISSING — pick or create a task within the existing initiative, link via task_id.","3. NEITHER-SET — match operator intent against existing initiatives by title+oneliner+module; if no clear match, CREATE a new initiative + 1-3 tasks decomposing the request, anchor to the FIRST task."],"creation_contract":{"initiative_file":".meshkore/roadmap/initiatives/<slug>.md — frontmatter id/title/status/priority/oneliner/modules/target/created/updated/owner/related + body sections `## Why this exists`, `## Done when`, `## Task plan`.","task_file":".meshkore/modules/<module>/tasks/<id>-<slug>.md — frontmatter id/title/status/priority/owner/category/initiative/created/updated/tags/depends_on/blocks + body sections `## Scope`, `## Done when`, `## Files`. Exactly one module per task (Standard §4).","slug_shape":"^[a-z][a-z0-9-]{1,31}$","task_id_shape":"^[A-Za-z][A-Za-z0-9_-]{1,31}$ (same as Standard §22 chat-id-references)"},"concurrency":"If three agents run in parallel and each creates its own initiative, three new initiatives appear in the Architect IDE's roadmap timeline simultaneously. Anchoring is independent — agents don't fight over the same anchor unless the architect explicitly dispatches them onto the same task.","out_of_scope":["Informational turns (`¿qué versión del daemon?`) — no anchor needed; the agent answers and stops.","Splitting / merging existing initiatives autonomously — the agent SUGGESTS, the operator approves.","Back-filling anchors for historical convs that ran before this rule shipped (v22 and earlier are grandfathered)."],"cockpit_alignment":"The Architect IDE's chat scope strip already shows the anchor. When an agent creates/swaps the anchor mid-conv, it must (a) persist file changes, (b) state the new anchor in chat using #<id> notation (Standard §22), (c) push to conv_meta via the daemon's edit path so the Architect IDE's badges follow in real time.","enforcement":"Prompt-level reinforcement (universal rules block in `Daemon._section_core_rules`, embedded in every briefing from py-1.12.23+). The daemon does NOT 4xx-reject unanchored dispatches yet — `text required` style hard rejects can come later if LLM drift becomes a problem.","convention":".meshkore/docs/conventions/initiative-anchored-execution.md","playbook":"https://meshkore.com/standard#24-initiative-anchored-execution-v23"},"agent_team":{"purpose":"Every cluster has a persistent roster of typed members from which working agent sessions are spawned. The team is what the operator means by 'my agents' — distinct from the code-level role registry (AGENT_PROMPTS), the per-conv runtime, and the declared external-agents store (.meshkore/agents/*.yaml). The default team is part of this standard; a conforming daemon MUST seed it when .meshkore/team/ is absent, then the operator owns it.","storage":".meshkore/team/<id>.md — one markdown file per member (frontmatter + init-prompt body).","model":{"member":"A definition file .meshkore/team/<id>.md with a mission, an init prompt, and a mandatory `model`. A template, not a running agent.","instance":"A chat conversation bound to a member via conv_meta.member. Each turn is a fresh `claude -p` briefed from the member's init prompt. The member binding is editable until the first dispatch, then freezes; model and effort stay editable for the whole conv and apply from the next turn.","kinds":{"singleton":"required:true — exactly two: architect-master (owns/maintains the roadmap; the 'CEO') and roadmap-orchestrator (executes the queue on Run All; wraps the legacy roadmap-architect role). Cannot be deleted; at most ONE live instance each.","profile":"One definition per role, but an UNLIMITED number of instances may run (developer, api-developer, ui-developer, deployer, ui-reviewer, commit-pr-reviewer, ...)."},"models_and_effort":"Every member's `model` defaults to the strongest available alias (an opus-tier alias so it tracks upgrades). `effort` (low/medium/high/max) is the usual per-member/per-instance tuning knob; operators downgrade the model only when they explicitly want to.","first_boot":"The agents column contains only the architect-master instance (the coordinator conv, bound to that member). Other members are started as instances by the operator."},"member_schema":{"file":".meshkore/team/<id>.md — frontmatter block + markdown body (the init prompt, injected as the instance's system prompt on the first turn).","fields":{"id":"^[a-z][a-z0-9-]{1,31}$ — MUST equal the filename stem","name":"string — display name (English UI)","emoji":"string — roster/avatar glyph","color":"string — hex accent","kind":"singleton | profile — immutable once seeded","required":"bool — true ⇒ cannot be deleted (only the two singletons); immutable once seeded","agent_type":"AGENT_PROMPTS baseline the prompt builder starts from","model":"MANDATORY — the strongest alias by default (lib/models.ts). A member with no model is non-conformant.","effort":"default | low | medium | high | max — the tuning knob","exposure":"internal | external — default internal (absent = internal). Whether the member is consumable as a service via the ask/poll surface (v30, external_exposure). Config, not a secret: committed in the member file. Orthogonal to `kind`. Enum leaves room for a future `mesh` value.","pinned_order":"int — roster sort key (ascending)","refs":"array of docs/workflows the member should read","credentials_hint":"path where secrets live (never inlined into the prompt)","created":"ISO date","updated":"ISO date"},"body":"Markdown init prompt: mission, how you work, limits. Injected as the instance's system prompt on the first turn."},"default_team":[{"id":"architect-master","kind":"singleton","required":true,"agent_type":"custom","mission":"Knows context/credentials/mission; creates & manages the roadmap (the 'CEO')."},{"id":"roadmap-orchestrator","kind":"singleton","required":true,"agent_type":"roadmap-architect","mission":"Executes the roadmap queue (Run All); dispatches worker instances."},{"id":"developer","kind":"profile","required":false,"agent_type":"custom","mission":"Generic, module-agnostic coder — the chat-rail '+' button's default member."},{"id":"api-developer","kind":"profile","required":false,"agent_type":"custom","mission":"Backend / API implementation."},{"id":"ui-developer","kind":"profile","required":false,"agent_type":"custom","mission":"Frontend / UI implementation."},{"id":"deployer","kind":"profile","required":false,"agent_type":"deploy","mission":"Deploys & release ops."},{"id":"ui-reviewer","kind":"profile","required":false,"agent_type":"review","mission":"Visual / functional review (uses MeshKore Verify POST /verify)."},{"id":"commit-pr-reviewer","kind":"profile","required":false,"agent_type":"review","mission":"Commit & PR review."},{"id":"consultant","kind":"profile","required":false,"agent_type":"custom","exposure":"external","mission":"Standing info point for external agents — social bots, collaborators, integrators. Answers about THIS project with cited facts from its docs/context/source; never invents; the caller owns voice and publishing. Ships exposure: external with a token pregenerated at scaffold/first-boot (v30)."}],"seeding":"The daemon MUST seed all nine members when .meshkore/team/ does not exist. Every member seeds with model = the strongest available alias (opus-tier today) and effort: default. `consultant` seeds with exposure: external and a pregenerated bearer token in .meshkore/credentials/team-tokens.yaml. Operators MAY edit init prompts, delete profile members, and add new ones; the two singletons cannot be deleted.","git_contract":".meshkore/team/ is project storage and IS committed under the v27 deny-list default (folder_layout.gitignore_contract). It is deliberately NOT in the deny-list; do not add it. The roster travels with the repo like docs/ and roadmap/initiatives/.","http_surface":{"GET /team":"list members","GET /team/<id>":"one member","POST /team":"create a member","PATCH /team/<id>":"update a member","DELETE /team/<id>":"delete a member — refuses required:true (the two singletons)","POST /team/draft":"turn free text into a structured member draft (new-member wizard backend)","team.* WS events":"team.created / team.updated / team.deleted push roster changes to connected cockpits"},"enforcement":"Dispatching a second live instance of a singleton member returns 409. A dispatch that arrives WITHOUT a `member` falls back to the legacy AGENT_PROMPTS[agent_type] path, so pre-v29 conversations keep working.","external_exposure":{"since":"30.0.0","purpose":"A team member with exposure: external is consumable as a service by other software on the same machine (another cluster, a bare Claude Code session, a bot pipeline) via an async ask/poll HTTP surface on the shared daemon.","token":{"storage":".meshkore/credentials/team-tokens.yaml ONLY (credentials/ is deny-listed in §2.2). The token MUST NEVER appear in the committed member file.","expiry":"NON-EXPIRING — no TTL, no rotation schedule. Lifecycle is operator-driven from the Team UI.","lifecycle":{"copy":"show + copy the token to hand to a consumer","rotate":"regenerate; the old token dies instantly","revoke":"one action: PATCH the member back to exposure: internal and the token is destroyed instantly — every outstanding ask 403s from that moment"},"scope":"ONLY the ask/poll surface for its own member. Not the portal token; grants nothing else."},"http_surface":{"POST /team/<id>/ask":"{text, session?} + Authorization: Bearer <member-token> + X-MeshKore-Project → 202 {request_id, conv}. Async because agent turns take 30 s – minutes.","GET /team/requests/<request_id>":"same auth → {status: queued|running|done|error, result_text, conv}","errors":"401 missing/unknown token · 403 token/member mismatch or member is exposure: internal (incl. post-revoke) · 404 unknown member or request id · 429 daemon at capacity (back off and retry)","session":"same `session` value → same conv → the member remembers the thread across asks","instances":"external asks are ORDINARY member instances: the conv appears in the chat rail, the init prompt is injected on turn 1, model/effort come from the member"},"a2a_card":"GET /team/<id>/.well-known/agent.json — served for every exposed member so any A2A-speaking client can self-configure.","perimeter":"v1 = loopback. The shared daemon binds loopback only (daemon_topology) — nothing off-machine can reach this surface; the token only discriminates between local callers. Cross-machine = future mesh exposure via identity (per-member did:key + hub registration), out of scope for v30. NOT port-forwarding.","convention":".meshkore/docs/conventions/team-external-requests.md"},"convention":".meshkore/docs/conventions/agent-team.md","playbook":"https://meshkore.com/standard#25-agent-team-v29"}}