{
  "$schema": "https://meshkore.com/standard.schema.json",
  "name": "MeshKore Standard",
  "version": "25.0.0",
  "updated": "2026-06-14",
  "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). Only this dir reaches git."
      },
      {
        "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": false,
        "purpose": "cross-cutting docs: architecture / product / conventions / deploy / security / ops"
      },
      {
        "path": "docs/INDEX.md",
        "committed": false,
        "purpose": "map only, no prose (R6)"
      },
      {
        "path": "docs/governance.md",
        "committed": false,
        "purpose": "thin pointer to https://meshkore.com/standard \u2014 never a duplicated copy"
      },
      {
        "path": "modules/<id>/",
        "committed": false,
        "purpose": "per-module bucket: README + tasks + log + diagrams"
      },
      {
        "path": "modules/<id>/tasks/<ID>-<slug>.md",
        "committed": false,
        "purpose": "active tasks for this module"
      },
      {
        "path": "modules/<id>/log/<YYYY-MM>/",
        "committed": false,
        "purpose": "archived (done) tasks, monthly buckets"
      },
      {
        "path": "modules/<id>/diagrams/",
        "committed": false,
        "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": false,
        "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/*",
      "!.meshkore/public/"
    ]
  },
  "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": {
          "protocol": {
            "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 \u2014 neither Run-all nor per-initiative dispatch will run code against it. Operator owns the draft \u2192 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
      }
    },
    "done_handling": "When status becomes 'done', move file from modules/<id>/tasks/ to modules/<id>/log/<YYYY-MM>/. Frontmatter unchanged."
  },
  "protocols": {
    "location": ".meshkore/protocols/",
    "purpose": "Reusable, indexed multi-step runbooks. Cross-cutting work that touches multiple scopes (docs + code + commit + deploy). When the operator says `apply P<N>`, an agent executes the Steps section and files a run log.",
    "identifier": "P<N> \u2014 letter-prefix-then-number, joining the cluster's existing T/V/D/C/N/AG family.",
    "file_naming": "P<N>-<slug>.md, one protocol 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/protocols/log/<YYYY-MM>/P<N>-<YYYY-MM-DD>-<context>.md",
      "frontmatter": {
        "required": [
          "protocol",
          "date",
          "operator",
          "agent",
          "outcome"
        ]
      }
    },
    "gitignore": "Commit the protocol files + INDEX.md; keep log/ local per machine.",
    "endpoints": {
      "GET  /protocols": "no-auth, list (id, title, scope, status, updated, log_count)",
      "GET  /protocols/<id>": "no-auth, raw markdown + parsed frontmatter",
      "GET  /protocols/<id>/runs": "no-auth, recent run-log entries (latest 50)",
      "WS broadcast": "protocols.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 \u00a76 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; cockpit posts to POST /debug/log and the daemon stamps src='cockpit'.",
      "retention": "30 minutes OR 5 MB, whichever ceiling hits first. Trim is atomic \u2014 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) \u2014 required",
        "src": "enum: daemon | cockpit | agent \u2014 required (server-forced to 'cockpit' for POST /debug/log)",
        "lvl": "enum: debug | info | warn | error \u2014 required",
        "tag": "kebab-case event category, dotted sub-namespaces allowed (e.g. architect-wake.skipped) \u2014 required",
        "msg": "human-readable line, <= 4000 chars \u2014 required",
        "conv": "conv id when conv-scoped \u2014 optional",
        "agent_id": "Axx-style label \u2014 optional",
        "data": "structured payload, token-like keys auto-redacted \u2014 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 \u2014 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 \u2014 actual age of the oldest event still on disk",
            "window_secs": "int \u2014 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='cockpit'; clients cannot forge src='daemon'",
          "response_shape": {
            "accepted": "int \u2014 number of events persisted"
          }
        }
      },
      "feature_detect": {
        "endpoint": "GET /health",
        "flag_path": "features.debug.stream.v1",
        "absent_means": "daemon predates py-1.10.17 \u2014 cockpit 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 anything under .meshkore/ outside public/.",
    "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 cockpit 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`."
  ],
  "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://meshkore.com/reference/cluster/scripts/daemon.py",
    "implementation": "python",
    "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. Any AI agent in an editor can curl-and-run it inside the repo.",
    "endpoints": {
      "GET  /health": "no-auth identity + cluster summary",
      "GET  /info": "no-auth /health + version + paths",
      "GET  /state": "no-auth filesystem-derived state.json",
      "GET  /reload": "bearer-auth rebuild + broadcast",
      "GET  /agents": "no-auth list of .meshkore/agents/*.yaml",
      "GET  /events": "WebSocket: hello, heartbeat, state.rebuilt, daemon.shutdown",
      "POST /shutdown": "bearer-auth graceful exit (the architect Stop button)"
    },
    "scope_today": "Single canonical L3 entry \u2014 read paths (visualization, file-derived state, multi-project listing, lifecycle) plus runner surface (agent dispatch, chat, headless claude --session-id, cron scheduling).",
    "stop_from_architect": "POST /shutdown with the bearer token from .meshkore/credentials/portal-token; the Projects rail Stop button does this."
  },
  "adding_projects": {
    "human_url": "https://meshkore.com/standard#10-3-adding-more-projects-to-your-architect",
    "modes": {
      "local": {
        "status": "available",
        "summary": "Paste the canonical prompt into an AI agent inside the new repo. The agent scaffolds .meshkore/, downloads the Python daemon, and starts it. Architect auto-detects via port scan.",
        "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"
      },
      "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 \u2014 see hand-off prompt.",
        "transport_change": "architect -> cloud relay (WSS) -> bridge daemon (on remote machine) -> local Python daemon",
        "daemon_contract_preserved": true,
        "out_of_scope_for_standard": [
          "auth",
          "billing",
          "rate-limiting",
          "bridge<->relay transport"
        ]
      }
    }
  },
  "multi_project": {
    "model": "per-folder daemon",
    "summary": "Each .meshkore/-shaped repo runs its own Python daemon on its own port. Daemons coexist on the same machine; the architect probes the range and lists them.",
    "port_range": [
      5570,
      5589
    ],
    "default_port": 5570,
    "port_resolution": "Try cluster.yaml.architect.port first; on conflict scan 5570-5589 for the first free port; persist chosen port to .meshkore/.runtime/port.",
    "switch_in_architect": "One-click via the leftmost Projects rail. Switching swaps DAEMON_BASE + WebSocket; no separate URL.",
    "isolation": "Each daemon watches only its own .meshkore/. No cross-project bleeding of state, members, credentials, or tasks.",
    "future_initiative": "single-daemon-multi-project \u2014 a single daemon process managing many projects under one port. Roadmap, not v6.0.0."
  },
  "validation": {
    "local_command": "python3 .meshkore/scripts/roadmap-build.py --validate",
    "checks": [
      "folder layout matches \u00a72",
      "public/cluster.yaml validates against \u00a73",
      "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 two-line contract from \u00a72.2"
    ],
    "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) \u2014 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 \u2014 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 \u2014 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 \u2192 vN`. Pair with `Section:` naming the top-level key changed.",
        "example": "Standard: v20 \u2192 v21"
      },
      "Section": {
        "required": false,
        "description": "Companion to `Standard:` \u2014 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 \u2014 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 \u2192 v21 \u2014 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 \u2192 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 \u2014 with the v21 `MeshKore:` addition \u2014 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` \u2014 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 cockpit'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 cockpit'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' \u2014 keeps the cockpit'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 \u2014 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 \u2014 equivalent to no documentation; CONTEXT tab renders blank.",
      "README.md exceeding 150 lines \u2014 split into sub-files under `.meshkore/modules/<id>/` instead of bloating one file.",
      "Missing frontmatter \u2014 the cockpit'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 \u2014 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 \u2014 never-do / always-do. Security + architectural. Bullet list."
      },
      "glossary.md": {
        "required": false,
        "max_words": 250,
        "purpose": "Domain terms \u2192 1-line definitions. Table form. Only terms the agent would otherwise misuse."
      },
      "decisions/": {
        "required": true,
        "growable": true,
        "purpose": "ADR-style log. Each file \u2264100 words: context \u2192 decision \u2192 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 \u2264100 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. Cockpit 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 \u2014 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 ===  \u2192 overview.md",
        "=== PRODUCT ===          \u2192 product.md",
        "=== STACK ===            \u2192 stack.md",
        "=== ARCHITECTURE ===     \u2192 architecture.md",
        "=== CONSTRAINTS ===      \u2192 constraints.md",
        "=== GLOSSARY ===         \u2192 glossary.md (skipped if missing)",
        "=== DECISIONS (newest first) === \u2192 decisions/*.md, sorted by date desc",
        "=== CRITERIA ===         \u2192 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 ===  \u2014 agents are instructed to treat everything above this marker as invariant."
    },
    "scope_exclusions": [
      "Audit procedure \u2192 lives in `.meshkore/protocols/` (operator-defined frequency, runbook).",
      "Credentials \u2192 lives in `.meshkore/credentials/` (gitignored) + `.meshkore/credentials.age` (sealed, optional).",
      "Bookmarks, crons, links, logs, config \u2014 each has its own `.meshkore/<storage>/`.",
      "Roadmap state (initiatives, tasks, status) \u2192 `.meshkore/roadmap/` + `.meshkore/modules/<id>/tasks/`. Volatile, not context.",
      "Module READMEs \u2192 `.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 \u2192 decisions/).",
        "A criterion / threshold (when X vs Y \u2192 criteria/).",
        "A domain term easy to misuse \u2192 glossary update."
      ],
      "skip_when": [
        "It's task state (lives in roadmap).",
        "It's audit/protocol 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 \u2014 context is bullets/tables/code-blocks, not prose.",
      "Marketing copy \u2014 context is internal, agent-targeted; no taglines.",
      "Duplicating module READMEs into context \u2014 module READMEs serve the Modules panel; context serves spawn-briefing. Different audiences.",
      "Volatile state in context \u2014 task progress, sprint goals, last-deployed-sha belong in roadmap/logs.",
      "Frontmatter bloat \u2014 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` \u2192 `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 \u2014 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 \u2014 returns { conv, version, items: [...] }",
      "POST /chat/conv/<conv>/queue": "enqueue \u2014 body { text }; returns the new item",
      "POST /chat/conv/<conv>/queue/<id>/edit": "edit \u2014 body { text }; 409 if item already dispatched",
      "POST /chat/conv/<conv>/queue/<id>/move": "reorder \u2014 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 \u2014 body: { conv, item, ts }",
      "queue.item.updated \u2014 body: { conv, item, ts } (edit OR move)",
      "queue.item.removed \u2014 body: { conv, item, ts }",
      "queue.item.sent \u2014 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 \u2014 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 \u2014 no extra storage.",
    "scope_exclusions": [
      "Not used by the architect or sub-agents to dispatch THEIR own work \u2014 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 \u2014 it isn't; it's transient.",
      "Auto-promoting all items in one round when the conv goes idle \u2014 only the HEAD pops per flush, by design (one turn = one item).",
      "Skipping the dispatch hand-off and writing directly to convMap \u2014 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 (\u00a711)."
    },
    "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 \u2014 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 \u2192 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 (\u00a79.1)",
      "Standard-evolution protocol pointer",
      "Mention of mesh primitives (Oracle, hub directory, /agent/<id> URL)",
      "Initiative-anchored execution rule (\u00a724) \u2014 locate-or-create (initiative, task) as the first action of an unanchored turn (v24)",
      "Pointers to the cluster's standing context (\u00a73.5 .meshkore/context/ incl. criteria/) and reusable runbooks (\u00a714 .meshkore/protocols/) (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 \u2014 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 \u2014 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 \u2014 { id, conv, agent_id, files }",
      "snapshot.removed \u2014 { 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 \u2014 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 \u2014 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> \u00b7 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 \u2014 retention drops old buckets.",
      "NOT a git replacement \u2014 commits remain the source of truth for merged history.",
      "NOT a transaction log \u2014 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 \u2014 all routes require the cluster's portal-token."
    ],
    "future_ui": "V108+ cockpit 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 cockpit. 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 cockpit. 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 cockpit 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 cockpit'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 cockpit 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 cockpit 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 cockpit'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 cockpit'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 cockpit'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 cockpit'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 cockpit'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"
  }
}
