diff --git a/.agents/skills/prompt-pack-maintainer b/.agents/skills/prompt-pack-maintainer new file mode 120000 index 0000000..9d1e7ad --- /dev/null +++ b/.agents/skills/prompt-pack-maintainer @@ -0,0 +1 @@ +../../skills/prompt-pack-maintainer \ No newline at end of file diff --git a/.github/workflows/check-prompts.yml b/.github/workflows/check-prompts.yml index f404e2e..bed49f3 100644 --- a/.github/workflows/check-prompts.yml +++ b/.github/workflows/check-prompts.yml @@ -5,6 +5,9 @@ on: branches: [main] paths: - "docs/prompts/**" + - "docs/contracts/**" + - "docs/ATLAS_CANVAS.md" + - "ROADMAP.md" - "exports/**" - "web/prompts.json" - "docs/prompts.json" @@ -15,6 +18,9 @@ on: branches: [main] paths: - "docs/prompts/**" + - "docs/contracts/**" + - "docs/ATLAS_CANVAS.md" + - "ROADMAP.md" - "exports/**" - "web/prompts.json" - "docs/prompts.json" @@ -23,6 +29,20 @@ on: - "CHANGELOG.md" jobs: + check-atlas-canvas: + name: Atlas Canvas contract check + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install contract validator + run: python -m pip install check-jsonschema + + - name: Validate Atlas Canvas contracts + run: bash scripts/check-atlas-canvas.sh + check-prompts: name: Prompt metadata check runs-on: ubuntu-latest diff --git a/ROADMAP.md b/ROADMAP.md index 7397c7c..245c0af 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -60,6 +60,7 @@ v1.3.0 — public status and release clarity (done) v1.4.0 — Save to brain, portable MQ_ROOT, prompt reorg (done) v1.5.0 — public repo hygiene and prompt-pack maturity (done) v2.0.0 — Atlas as a local prompt/workflow studio (next) +v2.1.0 — Atlas Canvas: structured Excalidraw workflows (planned) ``` Completed foundation: @@ -96,6 +97,7 @@ interaction patterns; mq-mcp remains the review/risk/architecture runtime. | v1.4.0 | Save to brain, portable MQ_ROOT, prompt reorg | Done | | v1.5.0 | Public repo hygiene and prompt-pack maturity | Done | | v2.0.0 | Atlas as a local prompt/workflow studio | Next | +| v2.1.0 | Atlas Canvas: structured Excalidraw workflows | Planned | --- @@ -849,6 +851,304 @@ the mq runtimes. --- +## v2.1.0 — Atlas Canvas: structured Excalidraw workflows + +Planned after v2.0.0. + +Goal: + +Turn Atlas reasoning modes and workflow sequences into editable Excalidraw +diagrams without making Atlas a model runtime, diagram renderer, review engine +or source of truth. Atlas owns intent, routing and the diagram request; +`excalidraw-ai-proxy` owns model access, streaming and Mermaid normalization; +Excalidraw owns canvas state and editing; mq-agent / mq-mcp own optional +execution, validation and review; mqobsidian owns durable curated records. + +### Target flow + +```text +User goal + ↓ +Atlas mode or workflow sequence + ↓ +atlas-diagram-request.v1 + ↓ +excalidraw-ai-proxy + ↓ +normalized Mermaid stream + ↓ +editable Excalidraw canvas + ↓ optional +mq-agent → mq-mcp review → annotations +``` + +### Architecture boundaries and ownership + +* [ ] Atlas One owns mode selection, workflow context, diagram intent, style + hints and user-visible handoff +* [ ] `excalidraw-ai-proxy` owns OpenAI credentials, model routing, prompt + limits, rate limits, SSE streaming and Mermaid repair +* [ ] Excalidraw owns element state, selection state, layout interaction, + editing, export and undo/redo +* [ ] mq-agent owns optional review/audit orchestration +* [ ] mq-mcp owns validation, safety classification and review contracts +* [ ] mqobsidian owns durable decisions and curated diagram references +* [ ] No browser surface receives an API key or calls a model provider directly +* [ ] No repo duplicates another repo's runtime or review logic + +### 1. Contract and compatibility spike + +Purpose: prove the smallest end-to-end path before adding product UI. + +* [x] Define `atlas-diagram-request.v1` with: + * request id and schema version + * goal and user-visible title + * Atlas mode or ordered workflow sequence + * diagram type and layout direction + * required concepts, relationships and boundaries + * style hints that remain advisory + * source/provenance metadata + * explicit validation and refinement intent +* [x] Define a versioned response envelope for success, validation failure, + timeout, rate limit and unsupported capability +* [x] Add JSON examples for `architect`, `analyze`, `decide`, `plan`, `debug` + and `review` +* [x] Confirm the existing proxy capability endpoint and + `POST /v1/ai/text-to-diagram/chat-streaming` support the handoff +* [ ] Build a local proof that sends one architecture request through the proxy + and imports the normalized Mermaid into Excalidraw +* [x] Record unsupported Excalidraw import or selection APIs before committing + to the refinement design +* [x] Reject unknown schema versions and malformed payloads with clear errors + +Proposed Atlas-owned files: + +```text +docs/contracts/atlas-diagram-request.v1.schema.json +docs/contracts/examples/atlas-diagram-architect.json +docs/contracts/examples/atlas-diagram-review.json +docs/ATLAS_CANVAS.md +``` + +### 2. Atlas mode-to-diagram composer + +Purpose: make diagram requests deterministic enough to review and test. + +* [ ] Map supported modes to diagram defaults: + * `architect` → architecture / trust-boundary diagram + * `analyze` → dependency or cause map + * `decide` → decision tree or option matrix + * `plan` → phased roadmap or process flow + * `debug` → diagnostic flow + * `review` → risk and control map +* [ ] Keep every default visible and editable before generation +* [ ] Compose requests from the resolved v2.0 workflow sequence when present +* [ ] Let users select diagram type, layout and included concerns explicitly +* [ ] Add deterministic fallbacks for modes without a dedicated mapping +* [ ] Prevent free-form Atlas content from becoming hidden system instructions +* [ ] Show the final request payload in a collapsible preview +* [ ] Add unit fixtures for every supported mode and fallback + +Proposed Atlas-owned files: + +```text +web/atlas-canvas.js +docs/atlas-canvas.js +docs/contracts/examples/ +scripts/check-atlas-canvas.sh +``` + +### 3. Open in Excalidraw MVP + +Purpose: deliver a useful one-way generation flow before bidirectional editing. + +* [ ] Add an `Open in Canvas` action beside copy and mq-agent execution +* [ ] Add a preflight check against the proxy capability endpoint +* [ ] Show unavailable, connecting, streaming, ready and failed states +* [ ] Stream generation progress without exposing raw provider responses +* [ ] Import the completed Mermaid into the configured local Excalidraw editor +* [ ] Preserve the original Atlas goal, mode and request id as safe metadata +* [ ] Provide copy/download fallback when Excalidraw is unavailable +* [ ] Avoid popup-only navigation; require an explicit user action +* [ ] Add keyboard access and screen-reader labels to the complete flow +* [ ] Document local ports and configuration without hardcoded private paths + +### 4. Excalidraw integration surface + +Purpose: keep the Excalidraw fork change small and upstream-aware. + +* [ ] Prefer supported Excalidraw import/library mechanisms over fork-specific + internals +* [ ] Add the smallest bridge needed to accept a versioned Atlas handoff +* [ ] Validate origin, payload size, schema version and allowed message types +* [ ] Require user confirmation before replacing or adding canvas content +* [ ] Preserve undo/redo for every Atlas-originated canvas mutation +* [ ] Store only non-sensitive provenance in element or scene metadata +* [ ] Add a visible `Generated from Atlas` source marker +* [ ] Document all fork-specific changes and likely upstream conflicts +* [ ] Add compatibility tests for the pinned Excalidraw revision + +### 5. Selection refinement loop + +Purpose: let users evolve a diagram without regenerating the whole scene. + +* [ ] Define `atlas-diagram-refinement.v1` for selected elements plus intent +* [ ] Support initial refinement actions: + * expand architecture + * add trust boundaries + * show dependencies + * show risks and controls + * simplify selected area + * turn selection into an implementation plan +* [ ] Send only the minimum selected context required for refinement +* [ ] Preview the proposed change before mutating the canvas +* [ ] Add or replace only the confirmed selection scope +* [ ] Preserve stable identifiers where possible +* [ ] Make every refinement undoable in one action +* [ ] Handle deleted, stale or unsupported selections safely +* [ ] Record request lineage without storing raw sensitive diagram content + +### 6. MQ validation and annotation loop + +Purpose: add evidence-backed review without moving review logic into Atlas. + +* [ ] Add a separate, explicit `Validate with MQ` action +* [ ] Convert the diagram into a compact review payload with source references +* [ ] Route validation through mq-agent to existing mq-mcp review contracts +* [ ] Keep validation read-only until the user accepts proposed annotations +* [ ] Map structured findings to annotation nodes for: + * fact + * assumption + * risk + * missing boundary + * recommendation +* [ ] Include finding id, severity, source and timestamp in safe metadata +* [ ] Never present model-generated annotations as verified facts +* [ ] Allow users to accept, dismiss or refresh findings individually +* [ ] Save durable decisions only through an mqobsidian handoff + +### 7. MQ visual library and theme + +Purpose: make generated diagrams recognizable and semantically consistent. + +* [ ] Define an `mq-amber-dark` theme with accessible contrast +* [ ] Define colors and line styles for facts, assumptions, risks, controls and + recommendations +* [ ] Create reusable components for mq-agent, mq-mcp, mqobsidian, mq-hal and + external providers +* [ ] Add curated Azure, Entra ID, Citrix and IGEL symbols only when licensing + permits redistribution +* [ ] Keep semantic role separate from visual style in the request contract +* [ ] Make every generated diagram usable without the custom library +* [ ] Version the library and document migration behavior + +### 8. Security, privacy and failure handling + +* [ ] Keep proxy binding on localhost by default +* [ ] Maintain explicit CORS allowlists for Atlas and Excalidraw origins +* [ ] Enforce request, prompt, image and response size limits +* [ ] Apply timeouts, cancellation and rate limiting to all generation flows +* [ ] Redact or reject secrets, tokens and private absolute paths before handoff +* [ ] Do not persist raw prompts, scenes or provider responses by default +* [ ] Treat imported Mermaid and diagram metadata as untrusted input +* [ ] Render errors as user-visible states without leaking credentials or + internal provider details +* [ ] Fail closed when capability negotiation or schema validation fails +* [ ] Add a public-safe scan before commit, release and generated-doc publish + +### 9. Test and release gates + +Atlas One gates: + +* [ ] Contract examples validate against their JSON schemas +* [ ] Every supported mode produces a valid deterministic request +* [ ] Unsupported modes use the documented fallback +* [ ] Static Pages mode remains useful without the local proxy +* [ ] `scripts/check-prompts.sh` continues to pass +* [ ] `scripts/check-docs.sh` continues to pass +* [ ] `scripts/check-atlas-canvas.sh` passes +* [ ] `scripts/release-check.sh` passes + +Integration gates: + +* [ ] Proxy health and capability preflight passes +* [ ] Text-to-diagram SSE success and error paths are tested +* [ ] Mermaid repair failures produce a safe, actionable error +* [ ] Excalidraw import preserves editable elements +* [ ] Selection refinement changes only confirmed scope and is undoable +* [ ] MQ review annotations preserve finding provenance +* [ ] Browser tests cover unavailable proxy, timeout, cancellation and retry +* [ ] No test or fixture contains real keys, private paths or sensitive scenes + +Release gates: + +* [ ] Pin and document compatible Atlas, proxy and Excalidraw versions +* [ ] Update README, ROADMAP, VERSION and CHANGELOG together +* [ ] Add installation, troubleshooting and rollback documentation +* [ ] Pass Atlas One, proxy and Excalidraw CI on the integration branches +* [ ] Complete manual smoke test on a clean local setup +* [ ] Publish a demo diagram containing no private infrastructure details + +### v2.1.0 definition of done + +* [ ] A user can turn an Atlas goal into an editable Excalidraw diagram +* [ ] Architect, analyze, decide, plan, debug and review modes are supported +* [ ] The request contract is versioned, documented and schema-validated +* [ ] Proxy capabilities are negotiated before generation +* [ ] A selected diagram region can be refined with preview and single-step undo +* [ ] MQ validation is explicit, read-only by default and provenance-preserving +* [ ] Static Atlas remains useful when local integration services are offline +* [ ] API keys remain server-side in `excalidraw-ai-proxy` +* [ ] Atlas contains no duplicated model, review or persistence runtime +* [ ] Accessibility, security, integration and release gates pass + +### Dependencies and build order + +```text +v2.0 workflow sequences + ↓ +1. Contract + compatibility spike + ↓ +2. Mode-to-diagram composer + ↓ +3. Open in Excalidraw MVP + ↓ +4. Excalidraw bridge hardening + ↓ +5. Selection refinement + ↓ +6. MQ validation annotations + ↓ +7. Visual library + release hardening +``` + +Steps 1–3 form the first releasable vertical slice. Steps 5–7 must not block a +safe one-way MVP. + +### Rollback + +* [ ] Keep Atlas Canvas behind a local feature flag until integration gates pass +* [ ] Preserve copy/export and mq-agent actions as independent fallbacks +* [ ] Make the Excalidraw bridge additive so it can be disabled without scene + migration +* [ ] Roll back by disabling the feature flag and reverting the integration + commits per owner repo; do not rewrite stored user scenes +* [ ] Keep all request schemas versioned so older clients fail clearly rather + than silently changing behavior + +### Out of scope + +* Atlas-side OpenAI or Ollama calls +* Autonomous canvas editing without preview and user confirmation +* Replacing Excalidraw's editor, scene model or export system +* Reimplementing mq-mcp review, safety or validation rules +* Persisting diagrams directly from Atlas into mqobsidian +* Real-time multi-user collaboration +* Cloud hosting, remote authentication or internet-exposed proxy deployment +* Automatic infrastructure deployment from a generated diagram + +--- + ## Long-term ideas These are intentionally not scheduled yet. @@ -868,7 +1168,6 @@ These are intentionally not scheduled yet. * shareable prompt URLs * multi-language prompt packs * Swedish Atlas One edition -* generated architecture diagrams * demo videos or GIFs --- diff --git a/docs/ATLAS_CANVAS.md b/docs/ATLAS_CANVAS.md new file mode 100644 index 0000000..00f1d2f --- /dev/null +++ b/docs/ATLAS_CANVAS.md @@ -0,0 +1,91 @@ +# Atlas Canvas + +Atlas Canvas is the planned handoff from Atlas reasoning modes and workflow +sequences to editable Excalidraw diagrams. + +## Ownership + +* Atlas One owns intent, mode/workflow routing and the versioned diagram request. +* `excalidraw-ai-proxy` owns provider credentials, model routing, limits, + streaming and Mermaid normalization. +* Excalidraw owns scene state, selection, editing, export and undo/redo. +* mq-agent and mq-mcp own optional orchestration, validation and review. +* mqobsidian owns durable curated records. + +Atlas must not call a model provider directly or duplicate proxy, review or +persistence logic. + +## Target flow + +```text +goal → Atlas route → atlas-diagram-request.v1 → proxy → Mermaid → Excalidraw +``` + +The request contract is defined in +[`contracts/atlas-diagram-request.v1.schema.json`](contracts/atlas-diagram-request.v1.schema.json). +Examples cover `analyze`, `architect`, `debug`, `decide`, `plan` and an ordered +`analyze → review` sequence. + +Workflow sequence order is the array order. Sequence items intentionally have +no separate step number, avoiding two competing sources of ordering truth. + +## Proxy compatibility + +The current proxy documents these integration points: + +* `GET /v1/ai/capabilities` for capability negotiation +* `POST /v1/ai/text-to-diagram/chat-streaming` for normalized Mermaid over SSE + +Compatibility was verified on 2026-07-16 against +`MCamner/excalidraw-ai-proxy` commit `98b9da1d52a8`. Its route tests confirm +that the capability endpoint advertises text-to-diagram support and that the +POST endpoint returns repaired Mermaid as buffered SSE `content` events, +followed by `done` and `[DONE]`. + +The proxy does not accept `atlas-diagram-request.v1` directly. Atlas must +validate that request locally, render its structured fields into one bounded +prompt and send the proxy wire request: + +```json +{ + "messages": [ + { "role": "user", "content": "" } + ] +} +``` + +The preflight is compatible when `features.textToDiagram` is `true`, +`features.streaming` is `true`, and `endpoints.textToDiagram` matches the +documented POST path. `streamingMode` is currently +`buffered-after-repair`, so Atlas must not claim token-by-token diagram +updates. The capability response does not negotiate Atlas schema versions; +schema compatibility remains Atlas-owned until the proxy exposes an explicit +version contract. + +Atlas should check capabilities before generation and treat all returned +content as untrusted. Credentials remain server-side in the proxy. + +Reproduce the proxy-side verification from a local proxy checkout with +`npm test`. The verified suite passed 21 tests, including capability metadata, +missing and oversized prompt rejection, normalized Mermaid SSE, empty output +and invalid Mermaid handling. This confirms transport compatibility through +the adapter above; it does not complete Excalidraw import. + +## Error model + +The integration must distinguish schema rejection, unsupported capability, +rate limiting, timeout, cancellation, upstream failure and Mermaid validation +failure. Atlas's proposed normalized envelope is defined in +[`contracts/atlas-diagram-response.v1.schema.json`](contracts/atlas-diagram-response.v1.schema.json). +It is an Atlas contract proposal, not a claim about the proxy's current wire +format, and must be agreed with the proxy owner before implementation. +Successful Mermaid content is limited to 200,000 characters at this Atlas +contract boundary; the proxy may enforce a lower runtime limit. + +## Open compatibility work + +The supported Excalidraw import, scene metadata and selection/refinement APIs +have not been verified against the pinned local checkout. The compatibility +spike must confirm them before the roadmap marks import or refinement complete. +No fork-specific API should be presented as stable until that verification is +recorded. diff --git a/docs/contracts/atlas-diagram-request.v1.schema.json b/docs/contracts/atlas-diagram-request.v1.schema.json new file mode 100644 index 0000000..d0a490b --- /dev/null +++ b/docs/contracts/atlas-diagram-request.v1.schema.json @@ -0,0 +1,136 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://mcamner.github.io/atlas-one/contracts/atlas-diagram-request.v1.schema.json", + "title": "Atlas Diagram Request v1", + "type": "object", + "additionalProperties": false, + "required": ["schema", "request_id", "goal", "title", "route", "diagram", "intent", "provenance"], + "properties": { + "schema": { "const": "atlas-diagram-request.v1" }, + "request_id": { "type": "string", "minLength": 1, "maxLength": 128 }, + "goal": { "type": "string", "minLength": 1, "maxLength": 6000 }, + "title": { "type": "string", "minLength": 1, "maxLength": 160 }, + "route": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["mode"], + "properties": { "mode": { "$ref": "#/$defs/mode" } } + }, + { + "type": "object", + "additionalProperties": false, + "required": ["sequence"], + "properties": { + "sequence": { + "type": "array", + "minItems": 1, + "maxItems": 12, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["mode"], + "properties": { + "mode": { "$ref": "#/$defs/mode" }, + "expected_output": { "type": "string", "minLength": 1, "maxLength": 500 } + } + } + } + } + } + ] + }, + "diagram": { + "type": "object", + "additionalProperties": false, + "required": ["type", "layout", "include", "relationships", "boundaries"], + "properties": { + "type": { + "enum": ["architecture", "cause-map", "decision-tree", "option-matrix", "roadmap", "process-flow", "diagnostic-flow", "risk-control-map"] + }, + "layout": { "enum": ["left-to-right", "top-to-bottom", "auto"] }, + "include": { + "type": "array", + "maxItems": 30, + "uniqueItems": true, + "items": { "type": "string", "minLength": 1, "maxLength": 160 } + }, + "relationships": { + "type": "array", + "maxItems": 60, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["from", "to", "label"], + "properties": { + "from": { "type": "string", "minLength": 1, "maxLength": 160 }, + "to": { "type": "string", "minLength": 1, "maxLength": 160 }, + "label": { "type": "string", "minLength": 1, "maxLength": 160 } + } + } + }, + "boundaries": { + "type": "array", + "maxItems": 20, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "contains"], + "properties": { + "name": { "type": "string", "minLength": 1, "maxLength": 160 }, + "contains": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "type": "string", "minLength": 1, "maxLength": 160 } + } + } + } + }, + "style_hints": { + "type": "object", + "description": "Advisory presentation hints; consumers may ignore them.", + "additionalProperties": false, + "properties": { + "theme": { "type": "string", "minLength": 1, "maxLength": 80 }, + "density": { "enum": ["compact", "balanced", "detailed"] } + } + } + } + }, + "intent": { + "type": "object", + "additionalProperties": false, + "required": ["operation", "validation"], + "properties": { + "operation": { "enum": ["generate", "refine"] }, + "validation": { "enum": ["schema-only", "proxy", "mq-review"] }, + "refinement": { "type": "string", "minLength": 1, "maxLength": 500 } + }, + "allOf": [ + { + "if": { "properties": { "operation": { "const": "refine" } } }, + "then": { "required": ["refinement"] }, + "else": { "not": { "required": ["refinement"] } } + } + ] + }, + "provenance": { + "type": "object", + "additionalProperties": false, + "required": ["producer", "created_at"], + "properties": { + "producer": { "const": "atlas-one" }, + "created_at": { "type": "string", "format": "date-time" }, + "workflow_pack_id": { "type": "string", "minLength": 1, "maxLength": 128 }, + "source_reference": { "type": "string", "minLength": 1, "maxLength": 500 } + } + } + }, + "$defs": { + "mode": { + "enum": ["analyze", "decide", "architect", "research", "explain", "teach", "edit", "coach", "plan", "debug", "review", "summarize", "create"] + } + } +} diff --git a/docs/contracts/atlas-diagram-response.v1.schema.json b/docs/contracts/atlas-diagram-response.v1.schema.json new file mode 100644 index 0000000..adf3c5e --- /dev/null +++ b/docs/contracts/atlas-diagram-response.v1.schema.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://mcamner.github.io/atlas-one/contracts/atlas-diagram-response.v1.schema.json", + "title": "Atlas Diagram Response v1", + "type": "object", + "additionalProperties": false, + "required": ["schema", "request_id", "status"], + "properties": { + "schema": { "const": "atlas-diagram-response.v1" }, + "request_id": { "type": "string", "minLength": 1, "maxLength": 128 }, + "status": { "enum": ["success", "request_validation_error", "diagram_validation_error", "unsupported", "rate_limited", "timeout", "cancelled", "upstream_error"] }, + "diagram": { + "type": "object", + "additionalProperties": false, + "required": ["format", "content"], + "properties": { + "format": { "const": "mermaid" }, + "content": { "type": "string", "minLength": 1, "maxLength": 200000 } + } + }, + "error": { + "type": "object", + "additionalProperties": false, + "required": ["code", "message", "retryable"], + "properties": { + "code": { "enum": ["invalid_request_schema", "unsupported_schema_version", "invalid_mermaid", "unsupported_capability", "rate_limit_exceeded", "generation_timeout", "generation_cancelled", "provider_failure"] }, + "message": { "type": "string", "minLength": 1, "maxLength": 500 }, + "retryable": { "type": "boolean" } + } + } + }, + "allOf": [ + { + "if": { "properties": { "status": { "const": "success" } } }, + "then": { "required": ["diagram"], "not": { "required": ["error"] } }, + "else": { "required": ["error"], "not": { "required": ["diagram"] } } + }, + { "if": { "properties": { "status": { "const": "request_validation_error" } } }, "then": { "properties": { "error": { "properties": { "code": { "enum": ["invalid_request_schema", "unsupported_schema_version"] } } } } } }, + { "if": { "properties": { "status": { "const": "diagram_validation_error" } } }, "then": { "properties": { "error": { "properties": { "code": { "const": "invalid_mermaid" } } } } } }, + { "if": { "properties": { "status": { "const": "unsupported" } } }, "then": { "properties": { "error": { "properties": { "code": { "const": "unsupported_capability" } } } } } }, + { "if": { "properties": { "status": { "const": "rate_limited" } } }, "then": { "properties": { "error": { "properties": { "code": { "const": "rate_limit_exceeded" } } } } } }, + { "if": { "properties": { "status": { "const": "timeout" } } }, "then": { "properties": { "error": { "properties": { "code": { "const": "generation_timeout" } } } } } }, + { "if": { "properties": { "status": { "const": "cancelled" } } }, "then": { "properties": { "error": { "properties": { "code": { "const": "generation_cancelled" } } } } } }, + { "if": { "properties": { "status": { "const": "upstream_error" } } }, "then": { "properties": { "error": { "properties": { "code": { "const": "provider_failure" } } } } } } + ] +} diff --git a/docs/contracts/examples/atlas-diagram-analyze.json b/docs/contracts/examples/atlas-diagram-analyze.json new file mode 100644 index 0000000..17ac610 --- /dev/null +++ b/docs/contracts/examples/atlas-diagram-analyze.json @@ -0,0 +1,16 @@ +{ + "schema": "atlas-diagram-request.v1", + "request_id": "atlas-example-analyze-001", + "goal": "Map the causes of repeated deployment failures.", + "title": "Deployment failure cause map", + "route": { "mode": "analyze" }, + "diagram": { + "type": "cause-map", + "layout": "left-to-right", + "include": ["symptoms", "candidate causes", "evidence", "unknowns"], + "relationships": [{ "from": "candidate causes", "to": "symptoms", "label": "may cause" }], + "boundaries": [{ "name": "evidence state", "contains": ["evidence", "unknowns"] }] + }, + "intent": { "operation": "generate", "validation": "schema-only" }, + "provenance": { "producer": "atlas-one", "created_at": "2026-07-16T00:00:00Z" } +} diff --git a/docs/contracts/examples/atlas-diagram-architect.json b/docs/contracts/examples/atlas-diagram-architect.json new file mode 100644 index 0000000..1b71e0c --- /dev/null +++ b/docs/contracts/examples/atlas-diagram-architect.json @@ -0,0 +1,28 @@ +{ + "schema": "atlas-diagram-request.v1", + "request_id": "atlas-example-architect-001", + "goal": "Design a secure local AI workflow with explicit trust boundaries.", + "title": "Local AI workflow architecture", + "route": { "mode": "architect" }, + "diagram": { + "type": "architecture", + "layout": "left-to-right", + "include": ["user", "atlas-one", "excalidraw-ai-proxy", "OpenAI", "Excalidraw", "trust boundaries"], + "relationships": [ + { "from": "atlas-one", "to": "excalidraw-ai-proxy", "label": "diagram request" }, + { "from": "excalidraw-ai-proxy", "to": "OpenAI", "label": "server-side model request" }, + { "from": "excalidraw-ai-proxy", "to": "Excalidraw", "label": "normalized Mermaid" } + ], + "boundaries": [ + { "name": "browser", "contains": ["atlas-one", "Excalidraw"] }, + { "name": "server-side credentials", "contains": ["excalidraw-ai-proxy"] } + ], + "style_hints": { "theme": "mq-amber-dark", "density": "balanced" } + }, + "intent": { "operation": "generate", "validation": "proxy" }, + "provenance": { + "producer": "atlas-one", + "created_at": "2026-07-16T00:00:00Z", + "source_reference": "docs/ATLAS_CANVAS.md" + } +} diff --git a/docs/contracts/examples/atlas-diagram-debug.json b/docs/contracts/examples/atlas-diagram-debug.json new file mode 100644 index 0000000..6c54165 --- /dev/null +++ b/docs/contracts/examples/atlas-diagram-debug.json @@ -0,0 +1,16 @@ +{ + "schema": "atlas-diagram-request.v1", + "request_id": "atlas-example-debug-001", + "goal": "Isolate why the local diagram proxy is unavailable.", + "title": "Proxy availability diagnosis", + "route": { "mode": "debug" }, + "diagram": { + "type": "diagnostic-flow", + "layout": "top-to-bottom", + "include": ["health check", "origin check", "configuration", "proxy logs", "result"], + "relationships": [{ "from": "health check", "to": "origin check", "label": "if healthy" }, { "from": "health check", "to": "configuration", "label": "if unavailable" }], + "boundaries": [{ "name": "read-only diagnostics", "contains": ["health check", "origin check", "proxy logs"] }] + }, + "intent": { "operation": "generate", "validation": "proxy" }, + "provenance": { "producer": "atlas-one", "created_at": "2026-07-16T00:00:00Z" } +} diff --git a/docs/contracts/examples/atlas-diagram-decide.json b/docs/contracts/examples/atlas-diagram-decide.json new file mode 100644 index 0000000..ce1f987 --- /dev/null +++ b/docs/contracts/examples/atlas-diagram-decide.json @@ -0,0 +1,16 @@ +{ + "schema": "atlas-diagram-request.v1", + "request_id": "atlas-example-decide-001", + "goal": "Compare two local deployment approaches.", + "title": "Deployment approach decision", + "route": { "mode": "decide" }, + "diagram": { + "type": "decision-tree", + "layout": "top-to-bottom", + "include": ["requirements", "option A", "option B", "tradeoffs", "decision"], + "relationships": [{ "from": "requirements", "to": "option A", "label": "evaluates" }, { "from": "requirements", "to": "option B", "label": "evaluates" }], + "boundaries": [{ "name": "decision inputs", "contains": ["requirements", "tradeoffs"] }] + }, + "intent": { "operation": "generate", "validation": "schema-only" }, + "provenance": { "producer": "atlas-one", "created_at": "2026-07-16T00:00:00Z" } +} diff --git a/docs/contracts/examples/atlas-diagram-plan.json b/docs/contracts/examples/atlas-diagram-plan.json new file mode 100644 index 0000000..bf08a8d --- /dev/null +++ b/docs/contracts/examples/atlas-diagram-plan.json @@ -0,0 +1,16 @@ +{ + "schema": "atlas-diagram-request.v1", + "request_id": "atlas-example-plan-001", + "goal": "Plan a safe staged rollout of Atlas Canvas.", + "title": "Atlas Canvas rollout", + "route": { "mode": "plan" }, + "diagram": { + "type": "roadmap", + "layout": "left-to-right", + "include": ["contract", "MVP", "refinement", "validation", "release"], + "relationships": [{ "from": "contract", "to": "MVP", "label": "enables" }, { "from": "MVP", "to": "refinement", "label": "precedes" }], + "boundaries": [{ "name": "first release slice", "contains": ["contract", "MVP"] }] + }, + "intent": { "operation": "generate", "validation": "schema-only" }, + "provenance": { "producer": "atlas-one", "created_at": "2026-07-16T00:00:00Z" } +} diff --git a/docs/contracts/examples/atlas-diagram-response-error.json b/docs/contracts/examples/atlas-diagram-response-error.json new file mode 100644 index 0000000..cae6a0b --- /dev/null +++ b/docs/contracts/examples/atlas-diagram-response-error.json @@ -0,0 +1,6 @@ +{ + "schema": "atlas-diagram-response.v1", + "request_id": "atlas-example-architect-001", + "status": "diagram_validation_error", + "error": { "code": "invalid_mermaid", "message": "Generated diagram could not be normalized.", "retryable": true } +} diff --git a/docs/contracts/examples/atlas-diagram-response-success.json b/docs/contracts/examples/atlas-diagram-response-success.json new file mode 100644 index 0000000..a9ea75f --- /dev/null +++ b/docs/contracts/examples/atlas-diagram-response-success.json @@ -0,0 +1,6 @@ +{ + "schema": "atlas-diagram-response.v1", + "request_id": "atlas-example-architect-001", + "status": "success", + "diagram": { "format": "mermaid", "content": "flowchart LR\n A[Atlas] --> B[Excalidraw]" } +} diff --git a/docs/contracts/examples/atlas-diagram-review.json b/docs/contracts/examples/atlas-diagram-review.json new file mode 100644 index 0000000..663d740 --- /dev/null +++ b/docs/contracts/examples/atlas-diagram-review.json @@ -0,0 +1,31 @@ +{ + "schema": "atlas-diagram-request.v1", + "request_id": "atlas-example-review-001", + "goal": "Review an architecture flow for missing controls and unclear ownership.", + "title": "Architecture risk and control review", + "route": { + "sequence": [ + { "mode": "analyze", "expected_output": "Dependencies and trust boundaries" }, + { "mode": "review", "expected_output": "Risks, controls and recommendations" } + ] + }, + "diagram": { + "type": "risk-control-map", + "layout": "top-to-bottom", + "include": ["facts", "assumptions", "risks", "controls", "recommendations"], + "relationships": [ + { "from": "risks", "to": "controls", "label": "mitigated by" }, + { "from": "facts", "to": "recommendations", "label": "supports" } + ], + "boundaries": [ + { "name": "verified", "contains": ["facts", "controls"] }, + { "name": "requires review", "contains": ["assumptions", "risks", "recommendations"] } + ] + }, + "intent": { "operation": "generate", "validation": "mq-review" }, + "provenance": { + "producer": "atlas-one", + "created_at": "2026-07-16T00:00:00Z", + "workflow_pack_id": "architecture-review" + } +} diff --git a/scripts/check-atlas-canvas.sh b/scripts/check-atlas-canvas.sh new file mode 100755 index 0000000..c6a3971 --- /dev/null +++ b/scripts/check-atlas-canvas.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +REQUEST_SCHEMA="$ROOT/docs/contracts/atlas-diagram-request.v1.schema.json" +RESPONSE_SCHEMA="$ROOT/docs/contracts/atlas-diagram-response.v1.schema.json" +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT + +validate() { + local schema="$1" + shift + if command -v check-jsonschema >/dev/null 2>&1; then + check-jsonschema --schemafile "$schema" "$@" + elif command -v uvx >/dev/null 2>&1; then + uvx check-jsonschema --schemafile "$schema" "$@" + else + echo "check-atlas-canvas: install check-jsonschema or uv" >&2 + return 2 + fi +} + +expect_invalid() { + local schema="$1" + local fixture="$2" + if validate "$schema" "$fixture" >/dev/null 2>&1; then + echo "check-atlas-canvas: expected invalid fixture: $fixture" >&2 + return 1 + fi +} + +validate "$REQUEST_SCHEMA" \ + "$ROOT"/docs/contracts/examples/atlas-diagram-{analyze,architect,debug,decide,plan,review}.json +validate "$RESPONSE_SCHEMA" \ + "$ROOT"/docs/contracts/examples/atlas-diagram-response-{success,error}.json + +jq '.schema = "atlas-diagram-request.v2"' \ + "$ROOT/docs/contracts/examples/atlas-diagram-architect.json" > "$TMP/unknown-version.json" +jq '.unexpected = true' \ + "$ROOT/docs/contracts/examples/atlas-diagram-architect.json" > "$TMP/extra-property.json" +jq '.intent = {"operation":"refine","validation":"schema-only"}' \ + "$ROOT/docs/contracts/examples/atlas-diagram-architect.json" > "$TMP/refine-without-intent.json" +jq '.error = {"code":"provider_failure","message":"unexpected","retryable":false}' \ + "$ROOT/docs/contracts/examples/atlas-diagram-response-success.json" > "$TMP/success-with-error.json" +jq '.error.code = "provider_failure"' \ + "$ROOT/docs/contracts/examples/atlas-diagram-response-error.json" > "$TMP/status-code-mismatch.json" +jq '.diagram.content = ("x" * 200001)' \ + "$ROOT/docs/contracts/examples/atlas-diagram-response-success.json" > "$TMP/oversized-diagram.json" + +expect_invalid "$REQUEST_SCHEMA" "$TMP/unknown-version.json" +expect_invalid "$REQUEST_SCHEMA" "$TMP/extra-property.json" +expect_invalid "$REQUEST_SCHEMA" "$TMP/refine-without-intent.json" +expect_invalid "$RESPONSE_SCHEMA" "$TMP/success-with-error.json" +expect_invalid "$RESPONSE_SCHEMA" "$TMP/status-code-mismatch.json" +expect_invalid "$RESPONSE_SCHEMA" "$TMP/oversized-diagram.json" + +echo "Atlas Canvas contracts: PASS"