From 498a9617939286abcdadf686d625c69a3d14c611 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Mon, 18 May 2026 16:17:19 +0000 Subject: [PATCH 01/36] docs: add living architecture guidance --- .cursor/rules/architecture-docs.mdc | 16 ++++ .github/copilot-instructions.md | 11 +++ AGENTS.md | 18 ++++ ARCHITECTURE.md | 87 +++++++++++++++++++ CLAUDE.md | 13 +++ GEMINI.md | 11 +++ docs/architecture/README.md | 44 ++++++++++ .../0001-living-architecture-docs.md | 24 +++++ .../templates/repo-architecture.md | 44 ++++++++++ 9 files changed, 268 insertions(+) create mode 100644 .cursor/rules/architecture-docs.mdc create mode 100644 .github/copilot-instructions.md create mode 100644 AGENTS.md create mode 100644 ARCHITECTURE.md create mode 100644 CLAUDE.md create mode 100644 GEMINI.md create mode 100644 docs/architecture/README.md create mode 100644 docs/architecture/decisions/0001-living-architecture-docs.md create mode 100644 docs/architecture/templates/repo-architecture.md diff --git a/.cursor/rules/architecture-docs.mdc b/.cursor/rules/architecture-docs.mdc new file mode 100644 index 00000000..f4f9a295 --- /dev/null +++ b/.cursor/rules/architecture-docs.mdc @@ -0,0 +1,16 @@ +--- +description: Keep architecture documentation current with code changes +globs: + - "**/*" +alwaysApply: true +--- + +Before non-trivial code changes, read the repository architecture context: + +- `AGENTS.md` +- `ARCHITECTURE.md` +- Relevant files under `docs/architecture/` + +When a change affects module boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, or build/test strategy, update the closest relevant architecture docs in the same change. + +If no architecture doc update is needed, say so explicitly in the final response or PR notes. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..6f335246 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,11 @@ +# Copilot Instructions + +Before making non-trivial code changes in this repository, read: + +- `AGENTS.md` +- `ARCHITECTURE.md` +- Relevant files under `docs/architecture/` + +Keep architecture documentation current with code changes. Update the closest relevant architecture file when a change affects boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, or build/test strategy. + +If a change is implementation-only and does not require architecture doc updates, mention that explicitly in PR notes. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..20124594 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,18 @@ +# Agent Instructions + +This repository uses living architecture documentation. Treat architecture docs like README docs: if a code change changes the shape, flow, boundaries, dependencies, public APIs, runtime model, or testing strategy, update the architecture docs in the same change. + +Before non-trivial code changes: + +1. Read `ARCHITECTURE.md`. +2. Read any relevant files under `docs/architecture/`. +3. Check `README.md` and tests relevant to the behavior being changed. + +When you change architecture-relevant behavior: + +- Update the closest relevant `ARCHITECTURE.md` or `docs/architecture/*.md` file. +- Add or update an ADR under `docs/architecture/decisions/` when the change records a durable design decision or tradeoff. +- Keep docs factual and current. Remove stale statements instead of adding contradictory notes. +- If no architecture doc update is needed, mention that explicitly in your final response or PR notes. + +`note-c` is a portable C SDK. Keep platform-specific behavior behind hooks or in adapter libraries unless the public architecture intentionally changes. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000..3e4aab23 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,87 @@ +# note-c Architecture + +This file is the architecture entrypoint for `note-c`. Keep it current when code changes alter system boundaries, public contracts, transport behavior, build/test strategy, or cross-repo expectations. + +## Purpose + +`note-c` is the portable C SDK for communicating with a Blues Notecard over serial or I2C. It owns the core request/response model, bundled JSON helpers, protocol framing, transport orchestration, and hook-based platform abstraction. + +`note-c` should remain platform-neutral. Platform-specific I/O, memory, timing, mutex, and logging behavior belongs behind hooks or in adapter libraries such as `note-arduino`, `note-posix`, `note-zephyr`, or `note-espidf`. + +## Major Components + +- `note.h`: public SDK API, version constants, hook typedefs, request helpers, and compatibility surface. +- `n_lib.h`: internal declarations shared across implementation files. +- `n_request.c`: request/response lifecycle, transaction orchestration, and high-level Notecard communication behavior. +- `n_serial.c`: serial transport implementation and chunked serial transmit/receive behavior. +- `n_i2c.c`: I2C transport implementation and chunked I2C transmit/receive behavior. +- `n_hooks.c`: registration and invocation of platform hooks for memory, time, mutexes, debug output, and transports. +- `n_cjson.c`, `n_cjson.h`, `n_cjson_helpers.c`: bundled JSON representation and helper APIs. +- `n_helpers.c`, `n_str.c`, `n_printf.c`, `n_atof.c`, `n_ftoa.c`, `n_b64.c`, `n_cobs.c`, `n_md5.c`, `n_const.c`, `n_ua.c`: portability helpers, encoding, formatting, constants, and utility behavior. +- `test/`: unit tests and mocks for protecting SDK behavior without requiring real hardware. +- `scripts/`: local automation for checks, documentation, and release support. + +## Data and Control Flow + +```text +application or adapter library + | + v +public API in note.h + | + v +request/response and JSON helpers + | + v +transport selection and chunking + | + v +registered serial or I2C hook + | + v +platform driver / hardware bus + | + v +Notecard +``` + +Applications normally build requests as `J` objects, send them through `NoteRequest`, `NoteRequestResponse`, or higher-level helpers, then release responses through the JSON/delete APIs. Transport and platform behavior is supplied through hooks so the same core code can run on microcontrollers, embedded Linux, tests, and other C/C++ environments. + +## Public Contracts + +The main compatibility contracts are: + +- Public functions, typedefs, constants, and macros in `note.h`. +- JSON object behavior exposed through `J` and helper functions. +- Hook signatures for serial, I2C, memory, mutex, time, and debug output. +- Notecard request/response semantics and timeout/retry behavior. +- Version constants and release expectations documented in `README.md`. + +Breaking changes to these contracts require deliberate versioning, migration notes, and architecture documentation updates. + +## Dependencies + +`note-c` is intentionally self-contained and portable. It vendors the JSON implementation and avoids mandatory platform runtime dependencies. Adapter repositories may embed or wrap this repository, including `note-arduino`, `note-zephyr`, `note-espidf`, and POSIX-focused integrations. + +## Runtime Model + +At runtime, host code initializes the relevant hooks, constructs Notecard requests, and calls `note-c` APIs. `note-c` serializes requests, sends bytes through the selected hook-backed transport, parses responses, and returns JSON objects or status to the caller. + +Unit tests use mocks to validate behavior without hardware. Hardware validation may be performed through adapter libraries or Notestation-backed workflows when bus-level or device-level behavior matters. + +## Testing Strategy + +Use the existing unit test suite for core request, JSON, hook, and transport behavior. Add or update tests when a change affects public APIs, retry/timeout behavior, memory ownership, transport chunking, or edge cases that can regress across adapter repositories. + +Before heavy Docker-based test runs in the OpenClaw workspace, follow the resource policy in the workspace `AGENTS.md` and run the resource check first. + +## Update Triggers + +Update this file or `docs/architecture/` when a change affects: + +- Public APIs or hook signatures. +- Transport framing, chunking, timeout, retry, or request lifecycle behavior. +- Memory ownership or allocation strategy. +- JSON representation or helper semantics. +- Cross-repo expectations for adapter libraries. +- Build, test, CI, release, or versioning strategy. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..c0c868d1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,13 @@ +# Claude Instructions + +This repository uses living architecture documentation. Treat these files as required context, the same way you would treat README files. + +Before non-trivial code changes: + +1. Read `AGENTS.md` for repository operating rules. +2. Read `ARCHITECTURE.md`. +3. Read relevant files under `docs/architecture/`. + +When a change affects architecture, update the docs in the same change. Architecture-relevant changes include module boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, and build/test strategy. + +If no architecture doc update is needed, say that explicitly in your final response or PR notes. diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 00000000..945eebbc --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,11 @@ +# Gemini Instructions + +This repository uses living architecture documentation. Treat these files as required context before non-trivial code changes: + +1. `AGENTS.md` +2. `ARCHITECTURE.md` +3. Relevant files under `docs/architecture/` + +When a change affects module boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, or build/test strategy, update the architecture docs in the same change. + +If no architecture doc update is needed, say so explicitly in the final response or PR notes. diff --git a/docs/architecture/README.md b/docs/architecture/README.md new file mode 100644 index 00000000..35070e1d --- /dev/null +++ b/docs/architecture/README.md @@ -0,0 +1,44 @@ +# Living Architecture Documentation + +Architecture docs are maintained with the code. Future agents and humans should be able to read these files before changing `note-c` and quickly understand the current system shape, boundaries, and tradeoffs. + +## Rules for Agents + +Before non-trivial code changes: + +1. Read the nearest applicable `AGENTS.md`, `CLAUDE.md`, or equivalent tool instruction file. +2. Read `ARCHITECTURE.md`. +3. Read relevant files under `docs/architecture/`. + +After code changes: + +- Update architecture docs when behavior, boundaries, dependencies, APIs, data flow, runtime topology, or testing strategy changes. +- Add an ADR for durable decisions that future maintainers should understand. +- Keep docs concise and factual. Prefer diagrams and lists over prose walls. +- Delete or rewrite stale architecture notes. Do not preserve obsolete statements just because they used to be true. +- If the change does not affect architecture, state that explicitly in the final response or PR notes. + +## File Types + +- `../../ARCHITECTURE.md`: repository-level architecture entrypoint. +- `decisions/*.md`: architecture decision records. +- `templates/repo-architecture.md`: template for future architecture docs. +- `../../AGENTS.md`, `../../CLAUDE.md`, `../../GEMINI.md`, `../../.github/copilot-instructions.md`, and `../../.cursor/rules/architecture-docs.mdc`: AI entrypoints that point future tools back to these docs. + +## What Belongs Here + +Architecture docs should capture: + +- Module responsibilities. +- Data/control flow between major components. +- Public contracts and compatibility constraints. +- Runtime and platform assumptions. +- Testing strategy for behavior that crosses module boundaries. +- Important tradeoffs, especially when there were plausible alternatives. + +Architecture docs should not become: + +- Full API reference. +- Changelog. +- Exhaustive file-by-file inventory. +- Raw meeting notes. diff --git a/docs/architecture/decisions/0001-living-architecture-docs.md b/docs/architecture/decisions/0001-living-architecture-docs.md new file mode 100644 index 00000000..8d06b58e --- /dev/null +++ b/docs/architecture/decisions/0001-living-architecture-docs.md @@ -0,0 +1,24 @@ +# 0001: Keep Living Architecture Docs With Code Changes + +## Status + +Accepted + +## Context + +AI agents and humans both need fast, current context before making changes to `note-c`. README files explain usage, but they do not reliably capture internal boundaries, design tradeoffs, cross-repo adapter expectations, or compatibility-sensitive public contracts. + +Because `note-c` is embedded by multiple Blues SDKs, architecture knowledge can drift unless it is maintained as part of normal code changes. + +## Decision + +Maintain architecture documentation as first-class repository content: + +- Use root `ARCHITECTURE.md` as the repository-level architecture entrypoint. +- Use `docs/architecture/` for maintenance rules, ADRs, and templates. +- Instruct future agents through `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, Copilot instructions, and Cursor rules to read and update these docs. +- Require architecture doc updates when code changes affect boundaries, dependencies, APIs, transport/runtime behavior, or testing strategy. + +## Consequences + +Architecture docs become part of the normal definition of done for architecture-relevant changes. Small implementation-only changes do not require doc churn, but the author should explicitly say the docs were considered. diff --git a/docs/architecture/templates/repo-architecture.md b/docs/architecture/templates/repo-architecture.md new file mode 100644 index 00000000..a2feae5d --- /dev/null +++ b/docs/architecture/templates/repo-architecture.md @@ -0,0 +1,44 @@ +# Repository Architecture + +Replace this template with the current architecture of the repository or subsystem. Keep it short enough that future agents will read it before making changes. + +## Purpose + +Describe what this code owns and what it deliberately does not own. + +## Major Components + +- `path/or/module`: responsibility. +- `path/or/module`: responsibility. + +## Data and Control Flow + +```text +caller + | + v +component + | + v +external system or dependency +``` + +## Public Contracts + +List APIs, file formats, protocols, hooks, or behavior that downstream users depend on. + +## Dependencies + +List important runtime, build, and test dependencies. Call out vendored or embedded dependencies and how they are updated. + +## Runtime Model + +Describe how the software runs in development, CI, production, or on hardware. + +## Testing Strategy + +Describe which tests protect which architectural contracts, and how to run them. + +## Update Triggers + +Update this file when changes affect module boundaries, public APIs, data/control flow, runtime topology, build/test/release workflow, or important cross-repo dependencies. From f9719b400402602a5185d36ccb217fb5ddfd1d5d Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Mon, 18 May 2026 16:51:07 +0000 Subject: [PATCH 02/36] docs: add architecture map artifacts --- .cursor/rules/architecture-docs.mdc | 4 +- .github/copilot-instructions.md | 4 +- AGENTS.md | 7 +- ARCHITECTURE.md | 7 + CLAUDE.md | 6 +- GEMINI.md | 6 +- docs/architecture/README.md | 4 + docs/architecture/architecture.html | 201 ++++++++++++++++++++++++++++ docs/architecture/architecture.json | 188 ++++++++++++++++++++++++++ 9 files changed, 419 insertions(+), 8 deletions(-) create mode 100644 docs/architecture/architecture.html create mode 100644 docs/architecture/architecture.json diff --git a/.cursor/rules/architecture-docs.mdc b/.cursor/rules/architecture-docs.mdc index f4f9a295..441e1409 100644 --- a/.cursor/rules/architecture-docs.mdc +++ b/.cursor/rules/architecture-docs.mdc @@ -9,8 +9,10 @@ Before non-trivial code changes, read the repository architecture context: - `AGENTS.md` - `ARCHITECTURE.md` +- `docs/architecture/architecture.json` +- `docs/architecture/architecture.html` when a visual overview helps - Relevant files under `docs/architecture/` -When a change affects module boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, or build/test strategy, update the closest relevant architecture docs in the same change. +When a change affects module boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, or build/test strategy, update the closest relevant architecture docs in the same change. Keep the Markdown, JSON, and HTML architecture maps synchronized when applicable. If no architecture doc update is needed, say so explicitly in the final response or PR notes. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 6f335246..38fb0282 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -4,8 +4,10 @@ Before making non-trivial code changes in this repository, read: - `AGENTS.md` - `ARCHITECTURE.md` +- `docs/architecture/architecture.json` +- `docs/architecture/architecture.html` when a visual overview helps - Relevant files under `docs/architecture/` -Keep architecture documentation current with code changes. Update the closest relevant architecture file when a change affects boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, or build/test strategy. +Keep architecture documentation current with code changes. Update the closest relevant architecture file when a change affects boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, or build/test strategy. Keep the Markdown, JSON, and HTML architecture maps synchronized when applicable. If a change is implementation-only and does not require architecture doc updates, mention that explicitly in PR notes. diff --git a/AGENTS.md b/AGENTS.md index 20124594..fe12bb69 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,12 +5,15 @@ This repository uses living architecture documentation. Treat architecture docs Before non-trivial code changes: 1. Read `ARCHITECTURE.md`. -2. Read any relevant files under `docs/architecture/`. -3. Check `README.md` and tests relevant to the behavior being changed. +2. Read `docs/architecture/architecture.json` for the structured map. +3. Read `docs/architecture/architecture.html` when a visual overview helps. +4. Read any other relevant files under `docs/architecture/`. +5. Check `README.md` and tests relevant to the behavior being changed. When you change architecture-relevant behavior: - Update the closest relevant `ARCHITECTURE.md` or `docs/architecture/*.md` file. +- Keep `docs/architecture/architecture.json` and `docs/architecture/architecture.html` synchronized with the Markdown architecture docs. - Add or update an ADR under `docs/architecture/decisions/` when the change records a durable design decision or tradeoff. - Keep docs factual and current. Remove stale statements instead of adding contradictory notes. - If no architecture doc update is needed, mention that explicitly in your final response or PR notes. diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 3e4aab23..5c92ea64 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,6 +2,11 @@ This file is the architecture entrypoint for `note-c`. Keep it current when code changes alter system boundaries, public contracts, transport behavior, build/test strategy, or cross-repo expectations. +Companion architecture artifacts: + +- `docs/architecture/architecture.html`: human-readable visual architecture map. +- `docs/architecture/architecture.json`: structured architecture map for AI agents and tooling. + ## Purpose `note-c` is the portable C SDK for communicating with a Blues Notecard over serial or I2C. It owns the core request/response model, bundled JSON helpers, protocol framing, transport orchestration, and hook-based platform abstraction. @@ -85,3 +90,5 @@ Update this file or `docs/architecture/` when a change affects: - JSON representation or helper semantics. - Cross-repo expectations for adapter libraries. - Build, test, CI, release, or versioning strategy. + +When updating architecture, keep this Markdown overview, `docs/architecture/architecture.html`, and `docs/architecture/architecture.json` consistent. diff --git a/CLAUDE.md b/CLAUDE.md index c0c868d1..2bb07514 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,8 +6,10 @@ Before non-trivial code changes: 1. Read `AGENTS.md` for repository operating rules. 2. Read `ARCHITECTURE.md`. -3. Read relevant files under `docs/architecture/`. +3. Read `docs/architecture/architecture.json` for the structured map. +4. Read `docs/architecture/architecture.html` when a visual overview helps. +5. Read relevant files under `docs/architecture/`. -When a change affects architecture, update the docs in the same change. Architecture-relevant changes include module boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, and build/test strategy. +When a change affects architecture, update the docs in the same change, including `ARCHITECTURE.md`, `docs/architecture/architecture.json`, and `docs/architecture/architecture.html` when applicable. Architecture-relevant changes include module boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, and build/test strategy. If no architecture doc update is needed, say that explicitly in your final response or PR notes. diff --git a/GEMINI.md b/GEMINI.md index 945eebbc..bff8c1c2 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -4,8 +4,10 @@ This repository uses living architecture documentation. Treat these files as req 1. `AGENTS.md` 2. `ARCHITECTURE.md` -3. Relevant files under `docs/architecture/` +3. `docs/architecture/architecture.json` +4. `docs/architecture/architecture.html` when a visual overview helps +5. Relevant files under `docs/architecture/` -When a change affects module boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, or build/test strategy, update the architecture docs in the same change. +When a change affects module boundaries, public APIs, hook signatures, dependencies, data/control flow, transport behavior, runtime assumptions, or build/test strategy, update the architecture docs in the same change, including the Markdown, JSON, and HTML architecture maps when applicable. If no architecture doc update is needed, say so explicitly in the final response or PR notes. diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 35070e1d..87538d55 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -21,6 +21,8 @@ After code changes: ## File Types - `../../ARCHITECTURE.md`: repository-level architecture entrypoint. +- `architecture.html`: single-file visual map for humans. +- `architecture.json`: structured map for AI agents and tooling. - `decisions/*.md`: architecture decision records. - `templates/repo-architecture.md`: template for future architecture docs. - `../../AGENTS.md`, `../../CLAUDE.md`, `../../GEMINI.md`, `../../.github/copilot-instructions.md`, and `../../.cursor/rules/architecture-docs.mdc`: AI entrypoints that point future tools back to these docs. @@ -36,6 +38,8 @@ Architecture docs should capture: - Testing strategy for behavior that crosses module boundaries. - Important tradeoffs, especially when there were plausible alternatives. +Keep `../../ARCHITECTURE.md`, `architecture.html`, and `architecture.json` synchronized when architecture changes. + Architecture docs should not become: - Full API reference. diff --git a/docs/architecture/architecture.html b/docs/architecture/architecture.html new file mode 100644 index 00000000..b00a4ffa --- /dev/null +++ b/docs/architecture/architecture.html @@ -0,0 +1,201 @@ + + + + + + note-c Architecture Map + + + +
+

note-c Architecture Map

+

Portable C SDK core for Notecard request/response behavior, hook-backed serial and I2C transports, and bundled JSON helpers.

+
+
+
+

Primary Request Flow

+
+
Application or adapterArduino, Zephyr, ESP-IDF, POSIX, tests
+
Public APInote.h
+
Request coren_request.c
+
JSON helpersn_cjson*
+
Transport selectionn_serial.cn_i2c.c
+
Registered hookn_hooks.c
+
Platform busUART, USB serial, I2C
+
NotecardJSON request/response device
+
+
+ +
+
+

Components

+
+
Public API

Compatibility surface: functions, typedefs, constants, hooks, version metadata.

note.h
public contract
+
Request/response core

Transaction orchestration, response parsing, timeout and retry behavior.

n_request.cn_lib.h
+
Platform hooks

Registration and invocation of platform-provided memory, time, mutex, debug, serial, and I2C callbacks.

n_hooks.c
public contract
+
Transports

Serial and I2C byte movement, framing, and chunking behavior.

n_serial.cn_i2c.c
+
JSON model

Bundled JSON object representation and helper functions used by callers and internals.

n_cjson.cn_cjson.hn_cjson_helpers.c
public contract
+
Portable helpers

Formatting, parsing, encoding, constants, user-agent support, and utility functions.

n_helpers.cn_str.cn_printf.cn_b64.cn_cobs.c
+
+
+ +
+

Design Principles

+
    +
  • Keep the SDK core platform-neutral.
  • +
  • Put platform behavior behind hooks or adapter libraries.
  • +
  • Treat note.h and hook signatures as compatibility contracts.
  • +
  • Use tests to protect public API, request lifecycle, memory ownership, and transport behavior.
  • +
+
+ +
+

External Boundaries

+
    +
  • Notecard: receives JSON requests and returns JSON responses over serial or I2C.
  • +
  • Notehub: cloud service reached by Notecard; note-c does not call it directly.
  • +
  • Adapter SDKs: note-arduino, note-zephyr, note-espidf, note-posix, and similar integrations supply platform behavior.
  • +
+
+ +
+

Update This Map When

+
    +
  • Public APIs, typedefs, constants, or hook signatures change.
  • +
  • Request lifecycle, timeout, retry, or memory ownership changes.
  • +
  • Serial/I2C framing, chunking, transmit, or receive behavior changes.
  • +
  • JSON helper semantics or adapter expectations change.
  • +
  • Build, test, release, or versioning strategy changes.
  • +
+
+
+
+ + + diff --git a/docs/architecture/architecture.json b/docs/architecture/architecture.json new file mode 100644 index 00000000..33491a28 --- /dev/null +++ b/docs/architecture/architecture.json @@ -0,0 +1,188 @@ +{ + "schemaVersion": "1.0", + "name": "note-c architecture map", + "repository": "blues/note-c", + "purpose": "Portable C SDK for communicating with a Blues Notecard over serial or I2C.", + "lastReviewed": "2026-05-18", + "principles": [ + "Keep the core SDK platform-neutral.", + "Put platform-specific behavior behind hooks or adapter libraries.", + "Treat note.h and hook signatures as compatibility contracts.", + "Update this map, architecture.html, and ARCHITECTURE.md when architecture-relevant code changes land." + ], + "components": [ + { + "id": "public-api", + "name": "Public API", + "paths": [ + "note.h" + ], + "responsibility": "Public functions, constants, typedefs, version metadata, request helpers, and hook contracts.", + "publicContract": true + }, + { + "id": "internal-api", + "name": "Internal declarations", + "paths": [ + "n_lib.h" + ], + "responsibility": "Private declarations shared across implementation files.", + "publicContract": false + }, + { + "id": "request-core", + "name": "Request/response core", + "paths": [ + "n_request.c" + ], + "responsibility": "Request lifecycle, transaction orchestration, response parsing, timeout/retry flow.", + "publicContract": false + }, + { + "id": "hooks", + "name": "Platform hooks", + "paths": [ + "n_hooks.c" + ], + "responsibility": "Registration and invocation of memory, mutex, timing, debug, serial, and I2C hooks.", + "publicContract": true + }, + { + "id": "serial-transport", + "name": "Serial transport", + "paths": [ + "n_serial.c" + ], + "responsibility": "Serial send/receive and chunked serial transport behavior.", + "publicContract": false + }, + { + "id": "i2c-transport", + "name": "I2C transport", + "paths": [ + "n_i2c.c" + ], + "responsibility": "I2C send/receive and chunked I2C transport behavior.", + "publicContract": false + }, + { + "id": "json", + "name": "JSON model and helpers", + "paths": [ + "n_cjson.c", + "n_cjson.h", + "n_cjson_helpers.c" + ], + "responsibility": "Bundled JSON object representation and helper APIs.", + "publicContract": true + }, + { + "id": "portable-helpers", + "name": "Portable helpers", + "paths": [ + "n_helpers.c", + "n_str.c", + "n_printf.c", + "n_atof.c", + "n_ftoa.c", + "n_b64.c", + "n_cobs.c", + "n_md5.c", + "n_const.c", + "n_ua.c" + ], + "responsibility": "Utility behavior, formatting/parsing helpers, encoding, constants, and user-agent support.", + "publicContract": false + }, + { + "id": "tests", + "name": "Unit tests", + "paths": [ + "test/" + ], + "responsibility": "Mock-backed tests for core SDK behavior without physical Notecard hardware.", + "publicContract": false + }, + { + "id": "docs", + "name": "Architecture and API docs", + "paths": [ + "ARCHITECTURE.md", + "docs/architecture/", + "docs/" + ], + "responsibility": "Human and agent-facing architecture, ADRs, and generated API documentation.", + "publicContract": false + } + ], + "flows": [ + { + "id": "request-flow", + "name": "Request flow", + "steps": [ + "application or adapter library", + "note.h public API", + "request/response core", + "JSON helpers", + "transport selection", + "serial or I2C hook", + "platform driver or hardware bus", + "Notecard" + ] + }, + { + "id": "hook-flow", + "name": "Hook initialization flow", + "steps": [ + "application or adapter library", + "hook registration API", + "n_hooks.c", + "transport/memory/time/mutex/debug callbacks", + "platform implementation" + ] + }, + { + "id": "test-flow", + "name": "Unit test flow", + "steps": [ + "test harness", + "mock hooks and transports", + "note-c core", + "asserted request, JSON, hook, or transport behavior" + ] + } + ], + "externalSystems": [ + { + "name": "Notecard", + "role": "Device that receives JSON requests and returns JSON responses over serial or I2C." + }, + { + "name": "Notehub", + "role": "Cloud service reached by Notecard; note-c does not communicate with Notehub directly." + }, + { + "name": "Adapter SDKs", + "examples": [ + "note-arduino", + "note-zephyr", + "note-espidf", + "note-posix" + ], + "role": "Provide platform-specific integration around note-c." + } + ], + "updateTriggers": [ + "Changes to note.h public APIs, typedefs, constants, or hook signatures.", + "Changes to request lifecycle, timeout, retry, memory ownership, or response handling.", + "Changes to serial/I2C framing, chunking, transmit, or receive behavior.", + "Changes to JSON representation or helper semantics.", + "Changes to adapter expectations, build/test strategy, release strategy, or versioning." + ], + "filesToUpdateTogether": [ + "ARCHITECTURE.md", + "docs/architecture/architecture.json", + "docs/architecture/architecture.html", + "docs/architecture/decisions/*.md when a durable design decision changes" + ] +} From 95df297c6a416c065b687346210bac6d7d944bd2 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Mon, 18 May 2026 18:25:02 +0000 Subject: [PATCH 03/36] docs: make architecture map visual --- docs/architecture/architecture.html | 602 +++++++++++++++++++++------- docs/architecture/architecture.json | 415 ++++++++++++++----- 2 files changed, 776 insertions(+), 241 deletions(-) diff --git a/docs/architecture/architecture.html b/docs/architecture/architecture.html index b00a4ffa..c0b7d032 100644 --- a/docs/architecture/architecture.html +++ b/docs/architecture/architecture.html @@ -7,195 +7,519 @@
-

note-c Architecture Map

-

Portable C SDK core for Notecard request/response behavior, hook-backed serial and I2C transports, and bundled JSON helpers.

+
+

note-c Architecture Map

+

A visual map of the portable SDK core: who calls it, what contracts it exposes, how requests move through JSON and transport layers, and where platform-specific behavior plugs in.

+
+
+ + + + +
+
-
-

Primary Request Flow

-
-
Application or adapterArduino, Zephyr, ESP-IDF, POSIX, tests
-
Public APInote.h
-
Request coren_request.c
-
JSON helpersn_cjson*
-
Transport selectionn_serial.cn_i2c.c
-
Registered hookn_hooks.c
-
Platform busUART, USB serial, I2C
-
NotecardJSON request/response device
+ + +
+
+
-
-
-

Components

-
-
Public API

Compatibility surface: functions, typedefs, constants, hooks, version metadata.

note.h
public contract
-
Request/response core

Transaction orchestration, response parsing, timeout and retry behavior.

n_request.cn_lib.h
-
Platform hooks

Registration and invocation of platform-provided memory, time, mutex, debug, serial, and I2C callbacks.

n_hooks.c
public contract
-
Transports

Serial and I2C byte movement, framing, and chunking behavior.

n_serial.cn_i2c.c
-
JSON model

Bundled JSON object representation and helper functions used by callers and internals.

n_cjson.cn_cjson.hn_cjson_helpers.c
public contract
-
Portable helpers

Formatting, parsing, encoding, constants, user-agent support, and utility functions.

n_helpers.cn_str.cn_printf.cn_b64.cn_cobs.c
-
-
- -
-

Design Principles

-
    -
  • Keep the SDK core platform-neutral.
  • -
  • Put platform behavior behind hooks or adapter libraries.
  • -
  • Treat note.h and hook signatures as compatibility contracts.
  • -
  • Use tests to protect public API, request lifecycle, memory ownership, and transport behavior.
  • -
-
- -
-

External Boundaries

-
    -
  • Notecard: receives JSON requests and returns JSON responses over serial or I2C.
  • -
  • Notehub: cloud service reached by Notecard; note-c does not call it directly.
  • -
  • Adapter SDKs: note-arduino, note-zephyr, note-espidf, note-posix, and similar integrations supply platform behavior.
  • -
-
- -
-

Update This Map When

-
    -
  • Public APIs, typedefs, constants, or hook signatures change.
  • -
  • Request lifecycle, timeout, retry, or memory ownership changes.
  • -
  • Serial/I2C framing, chunking, transmit, or receive behavior changes.
  • -
  • JSON helper semantics or adapter expectations change.
  • -
  • Build, test, release, or versioning strategy changes.
  • -
-
-
+
+ + - diff --git a/docs/architecture/architecture.json b/docs/architecture/architecture.json index 33491a28..8b1e2ff1 100644 --- a/docs/architecture/architecture.json +++ b/docs/architecture/architecture.json @@ -1,86 +1,147 @@ { - "schemaVersion": "1.0", + "schemaVersion": "1.1", "name": "note-c architecture map", "repository": "blues/note-c", "purpose": "Portable C SDK for communicating with a Blues Notecard over serial or I2C.", "lastReviewed": "2026-05-18", + "viewArtifacts": { + "humanMap": "docs/architecture/architecture.html", + "agentMap": "docs/architecture/architecture.json", + "narrative": "ARCHITECTURE.md" + }, "principles": [ "Keep the core SDK platform-neutral.", "Put platform-specific behavior behind hooks or adapter libraries.", "Treat note.h and hook signatures as compatibility contracts.", - "Update this map, architecture.html, and ARCHITECTURE.md when architecture-relevant code changes land." + "Update the Markdown, HTML, and JSON maps when architecture-relevant code changes land." ], - "components": [ + "layers": [ { - "id": "public-api", - "name": "Public API", - "paths": [ - "note.h" - ], - "responsibility": "Public functions, constants, typedefs, version metadata, request helpers, and hook contracts.", - "publicContract": true + "id": "consumers", + "name": "Consumers and adapters", + "role": "Applications, platform SDKs, and tests that call note-c." }, { - "id": "internal-api", - "name": "Internal declarations", - "paths": [ - "n_lib.h" - ], - "responsibility": "Private declarations shared across implementation files.", - "publicContract": false + "id": "api", + "name": "Public contract", + "role": "The API and hook surface downstream code depends on." }, { - "id": "request-core", - "name": "Request/response core", - "paths": [ - "n_request.c" - ], - "responsibility": "Request lifecycle, transaction orchestration, response parsing, timeout/retry flow.", - "publicContract": false + "id": "core", + "name": "Portable core", + "role": "Request lifecycle, JSON, helpers, binary codecs, and utility behavior." }, { - "id": "hooks", - "name": "Platform hooks", + "id": "transport", + "name": "Transport and hooks", + "role": "Transport selection, chunking, and platform callback boundaries." + }, + { + "id": "external", + "name": "Hardware and cloud boundary", + "role": "Physical bus, Notecard, and Notehub reached by the Notecard." + } + ], + "nodes": [ + { + "id": "apps", + "layer": "consumers", + "name": "Applications", + "kind": "consumer", + "paths": [], + "summary": "User firmware or host apps that build requests and consume responses.", + "contracts": [ + "Calls public APIs in note.h" + ] + }, + { + "id": "adapters", + "layer": "consumers", + "name": "Adapter SDKs", + "kind": "consumer", + "paths": [], + "summary": "Platform integrations such as note-arduino, note-zephyr, note-espidf, and POSIX integrations.", + "contracts": [ + "Own platform setup and hook implementations" + ] + }, + { + "id": "tests", + "layer": "consumers", + "name": "Unit Tests", + "kind": "test", "paths": [ - "n_hooks.c" + "test/" ], - "responsibility": "Registration and invocation of memory, mutex, timing, debug, serial, and I2C hooks.", - "publicContract": true + "summary": "Mock-backed tests for JSON, request flow, hooks, transports, helpers, and edge cases.", + "contracts": [ + "Protects behavior without hardware" + ] }, { - "id": "serial-transport", - "name": "Serial transport", + "id": "api", + "layer": "api", + "name": "note.h Public API", + "kind": "contract", "paths": [ - "n_serial.c" + "note.h" ], - "responsibility": "Serial send/receive and chunked serial transport behavior.", - "publicContract": false + "summary": "Public functions, typedefs, constants, version metadata, request helpers, and hook signatures.", + "contracts": [ + "Compatibility boundary", + "Breaking changes require versioning and migration notes" + ] }, { - "id": "i2c-transport", - "name": "I2C transport", + "id": "request", + "layer": "core", + "name": "Request Core", + "kind": "core", "paths": [ - "n_i2c.c" + "n_request.c", + "n_lib.h" ], - "responsibility": "I2C send/receive and chunked I2C transport behavior.", - "publicContract": false + "summary": "Creates, serializes, sends, retries, parses, and releases Notecard request/response transactions.", + "contracts": [ + "Owns transaction lifecycle", + "Coordinates active interface" + ] }, { "id": "json", - "name": "JSON model and helpers", + "layer": "core", + "name": "JSON Model", + "kind": "core", "paths": [ "n_cjson.c", "n_cjson.h", "n_cjson_helpers.c" ], - "responsibility": "Bundled JSON object representation and helper APIs.", - "publicContract": true + "summary": "Bundled JSON object model and helper APIs used by callers and internals.", + "contracts": [ + "J object semantics", + "Allocation ownership" + ] + }, + { + "id": "helpers", + "layer": "core", + "name": "High-level Helpers", + "kind": "core", + "paths": [ + "n_helpers.c" + ], + "summary": "Convenience APIs for common Notecard operations: time, env, location, sync, payload, binary store, and status helpers.", + "contracts": [ + "Builds JSON requests on top of public request APIs" + ] }, { - "id": "portable-helpers", - "name": "Portable helpers", + "id": "utilities", + "layer": "core", + "name": "Portable Utilities", + "kind": "core", "paths": [ - "n_helpers.c", "n_str.c", "n_printf.c", "n_atof.c", @@ -91,91 +152,241 @@ "n_const.c", "n_ua.c" ], - "responsibility": "Utility behavior, formatting/parsing helpers, encoding, constants, and user-agent support.", - "publicContract": false + "summary": "String, number, formatting, encoding, hashing, constants, and user-agent support.", + "contracts": [ + "No platform runtime assumptions" + ] }, { - "id": "tests", - "name": "Unit tests", + "id": "hooks", + "layer": "transport", + "name": "Platform Hooks", + "kind": "hook", "paths": [ - "test/" + "n_hooks.c" ], - "responsibility": "Mock-backed tests for core SDK behavior without physical Notecard hardware.", - "publicContract": false + "summary": "Registration and invocation of memory, time, mutex, debug, transaction, serial, I2C, and JSON transaction callbacks.", + "contracts": [ + "Platform boundary", + "Hook signatures are public contracts" + ] }, { - "id": "docs", - "name": "Architecture and API docs", + "id": "serial", + "layer": "transport", + "name": "Serial Transport", + "kind": "transport", "paths": [ - "ARCHITECTURE.md", - "docs/architecture/", - "docs/" + "n_serial.c" ], - "responsibility": "Human and agent-facing architecture, ADRs, and generated API documentation.", - "publicContract": false - } - ], - "flows": [ - { - "id": "request-flow", - "name": "Request flow", - "steps": [ - "application or adapter library", - "note.h public API", - "request/response core", - "JSON helpers", - "transport selection", - "serial or I2C hook", - "platform driver or hardware bus", - "Notecard" + "summary": "Serial transaction, reset, receive, transmit, and chunking behavior.", + "contracts": [ + "Uses serial hooks", + "Protects byte-level request/response flow" ] }, { - "id": "hook-flow", - "name": "Hook initialization flow", - "steps": [ - "application or adapter library", - "hook registration API", - "n_hooks.c", - "transport/memory/time/mutex/debug callbacks", - "platform implementation" + "id": "i2c", + "layer": "transport", + "name": "I2C Transport", + "kind": "transport", + "paths": [ + "n_i2c.c" + ], + "summary": "I2C transaction, reset, query length, receive, transmit, MTU, and chunking behavior.", + "contracts": [ + "Uses I2C hooks", + "Owns I2C timing and chunking behavior" ] }, { - "id": "test-flow", - "name": "Unit test flow", - "steps": [ - "test harness", - "mock hooks and transports", - "note-c core", - "asserted request, JSON, hook, or transport behavior" + "id": "bus", + "layer": "external", + "name": "Platform Bus", + "kind": "external", + "paths": [], + "summary": "UART, USB serial, I2C, or test doubles supplied by the host platform.", + "contracts": [ + "Implemented outside note-c" ] - } - ], - "externalSystems": [ + }, { + "id": "notecard", + "layer": "external", "name": "Notecard", - "role": "Device that receives JSON requests and returns JSON responses over serial or I2C." + "kind": "external", + "paths": [], + "summary": "Device that accepts JSON requests and returns JSON responses.", + "contracts": [ + "Serial or I2C protocol boundary" + ] }, { + "id": "notehub", + "layer": "external", "name": "Notehub", - "role": "Cloud service reached by Notecard; note-c does not communicate with Notehub directly." + "kind": "external", + "paths": [], + "summary": "Cloud service reached by the Notecard; note-c does not communicate with Notehub directly.", + "contracts": [ + "Indirect dependency only" + ] + } + ], + "edges": [ + { + "from": "apps", + "to": "api", + "label": "calls" }, { - "name": "Adapter SDKs", - "examples": [ - "note-arduino", - "note-zephyr", - "note-espidf", - "note-posix" + "from": "adapters", + "to": "api", + "label": "wraps" + }, + { + "from": "tests", + "to": "api", + "label": "exercises" + }, + { + "from": "api", + "to": "request", + "label": "request APIs" + }, + { + "from": "api", + "to": "json", + "label": "J helpers" + }, + { + "from": "api", + "to": "hooks", + "label": "hook registration" + }, + { + "from": "helpers", + "to": "request", + "label": "builds requests" + }, + { + "from": "request", + "to": "json", + "label": "serialize/parse" + }, + { + "from": "request", + "to": "hooks", + "label": "active interface" + }, + { + "from": "request", + "to": "serial", + "label": "serial path" + }, + { + "from": "request", + "to": "i2c", + "label": "I2C path" + }, + { + "from": "serial", + "to": "hooks", + "label": "serial callbacks" + }, + { + "from": "i2c", + "to": "hooks", + "label": "I2C callbacks" + }, + { + "from": "hooks", + "to": "bus", + "label": "platform calls" + }, + { + "from": "bus", + "to": "notecard", + "label": "bytes" + }, + { + "from": "notecard", + "to": "notehub", + "label": "syncs" + }, + { + "from": "tests", + "to": "hooks", + "label": "mocks" + }, + { + "from": "tests", + "to": "serial", + "label": "transport tests" + }, + { + "from": "tests", + "to": "i2c", + "label": "transport tests" + }, + { + "from": "utilities", + "to": "request", + "label": "support" + }, + { + "from": "utilities", + "to": "json", + "label": "support" + } + ], + "hotspots": [ + { + "id": "public-api", + "title": "Public API and hook compatibility", + "nodes": [ + "api", + "hooks" + ], + "updateRule": "Update docs and consider versioning whenever note.h contracts change." + }, + { + "id": "transaction-flow", + "title": "Request lifecycle", + "nodes": [ + "request", + "json", + "serial", + "i2c" + ], + "updateRule": "Update docs when timeout, retry, serialization, parsing, memory ownership, or active-interface behavior changes." + }, + { + "id": "transport-boundary", + "title": "Transport and platform boundary", + "nodes": [ + "serial", + "i2c", + "hooks", + "bus" + ], + "updateRule": "Update docs when byte framing, chunking, MTU, reset, or hook invocation semantics change." + }, + { + "id": "adapter-impact", + "title": "Adapter impact", + "nodes": [ + "adapters", + "api", + "hooks" ], - "role": "Provide platform-specific integration around note-c." + "updateRule": "Update docs when note-arduino, note-zephyr, note-espidf, POSIX, or other adapters need coordinated changes." } ], "updateTriggers": [ "Changes to note.h public APIs, typedefs, constants, or hook signatures.", "Changes to request lifecycle, timeout, retry, memory ownership, or response handling.", - "Changes to serial/I2C framing, chunking, transmit, or receive behavior.", + "Changes to serial/I2C framing, chunking, transmit, receive, reset, or MTU behavior.", "Changes to JSON representation or helper semantics.", "Changes to adapter expectations, build/test strategy, release strategy, or versioning." ], From e0e16492c9d9cfee64a33b6036b936c0e3ab99cb Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Thu, 21 May 2026 15:17:07 +0000 Subject: [PATCH 04/36] Zoom out architecture map --- docs/architecture/architecture.html | 34 +++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/docs/architecture/architecture.html b/docs/architecture/architecture.html index c0b7d032..28c2666f 100644 --- a/docs/architecture/architecture.html +++ b/docs/architecture/architecture.html @@ -20,6 +20,7 @@ --red: #b42318; --violet: #6750a4; --shadow: 0 14px 32px rgba(23, 32, 38, 0.12); + --map-scale: 0.69; } * { box-sizing: border-box; } body { @@ -64,7 +65,7 @@ } main { display: grid; - grid-template-columns: 270px 1fr 330px; + grid-template-columns: 220px 1fr 280px; gap: 16px; padding: 16px; height: calc(100vh - 92px); @@ -136,9 +137,18 @@ } .map { position: relative; + width: 800px; + height: 497px; + margin: 0 auto; + } + .map-canvas { + position: absolute; + left: 0; + top: 0; width: 1160px; height: 720px; - margin: 0 auto; + transform: scale(var(--map-scale)); + transform-origin: left top; } .layer { position: absolute; @@ -325,15 +335,17 @@

note-c Architecture Map

-
- +
+
+ +
From 6380d5e82728ab1674339b61988e07bfd9b70ab9 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Thu, 21 May 2026 15:23:25 +0000 Subject: [PATCH 05/36] Spread architecture map rows --- docs/architecture/architecture.html | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/architecture/architecture.html b/docs/architecture/architecture.html index 28c2666f..aa10fab6 100644 --- a/docs/architecture/architecture.html +++ b/docs/architecture/architecture.html @@ -138,7 +138,7 @@ .map { position: relative; width: 800px; - height: 497px; + height: 690px; margin: 0 auto; } .map-canvas { @@ -146,7 +146,7 @@ left: 0; top: 0; width: 1160px; - height: 720px; + height: 1000px; transform: scale(var(--map-scale)); transform-origin: left top; } @@ -154,7 +154,7 @@ position: absolute; left: 24px; right: 24px; - height: 116px; + height: 148px; border: 1px dashed #b7c6cf; border-radius: 8px; background: rgba(255,255,255,0.68); @@ -337,7 +337,7 @@

note-c Architecture Map

-

note-c Architecture Map

const architecture = {"schemaVersion":"1.1","name":"note-c architecture map","repository":"blues/note-c","purpose":"Portable C SDK for communicating with a Blues Notecard over serial or I2C.","lastReviewed":"2026-05-18","viewArtifacts":{"humanMap":"docs/architecture/architecture.html","agentMap":"docs/architecture/architecture.json","narrative":"ARCHITECTURE.md"},"principles":["Keep the core SDK platform-neutral.","Put platform-specific behavior behind hooks or adapter libraries.","Treat note.h and hook signatures as compatibility contracts.","Update the Markdown, HTML, and JSON maps when architecture-relevant code changes land."],"layers":[{"id":"consumers","name":"Consumers and adapters","role":"Applications, platform SDKs, and tests that call note-c."},{"id":"api","name":"Public contract","role":"The API and hook surface downstream code depends on."},{"id":"core","name":"Portable core","role":"Request lifecycle, JSON, helpers, binary codecs, and utility behavior."},{"id":"transport","name":"Transport and hooks","role":"Transport selection, chunking, and platform callback boundaries."},{"id":"external","name":"Hardware and cloud boundary","role":"Physical bus, Notecard, and Notehub reached by the Notecard."}],"nodes":[{"id":"apps","layer":"consumers","name":"Applications","kind":"consumer","paths":[],"summary":"User firmware or host apps that build requests and consume responses.","contracts":["Calls public APIs in note.h"]},{"id":"adapters","layer":"consumers","name":"Adapter SDKs","kind":"consumer","paths":[],"summary":"Platform integrations such as note-arduino, note-zephyr, note-espidf, and POSIX integrations.","contracts":["Own platform setup and hook implementations"]},{"id":"tests","layer":"consumers","name":"Unit Tests","kind":"test","paths":["test/"],"summary":"Mock-backed tests for JSON, request flow, hooks, transports, helpers, and edge cases.","contracts":["Protects behavior without hardware"]},{"id":"api","layer":"api","name":"note.h Public API","kind":"contract","paths":["note.h"],"summary":"Public functions, typedefs, constants, version metadata, request helpers, and hook signatures.","contracts":["Compatibility boundary","Breaking changes require versioning and migration notes"]},{"id":"request","layer":"core","name":"Request Core","kind":"core","paths":["n_request.c","n_lib.h"],"summary":"Creates, serializes, sends, retries, parses, and releases Notecard request/response transactions.","contracts":["Owns transaction lifecycle","Coordinates active interface"]},{"id":"json","layer":"core","name":"JSON Model","kind":"core","paths":["n_cjson.c","n_cjson.h","n_cjson_helpers.c"],"summary":"Bundled JSON object model and helper APIs used by callers and internals.","contracts":["J object semantics","Allocation ownership"]},{"id":"helpers","layer":"core","name":"High-level Helpers","kind":"core","paths":["n_helpers.c"],"summary":"Convenience APIs for common Notecard operations: time, env, location, sync, payload, binary store, and status helpers.","contracts":["Builds JSON requests on top of public request APIs"]},{"id":"utilities","layer":"core","name":"Portable Utilities","kind":"core","paths":["n_str.c","n_printf.c","n_atof.c","n_ftoa.c","n_b64.c","n_cobs.c","n_md5.c","n_const.c","n_ua.c"],"summary":"String, number, formatting, encoding, hashing, constants, and user-agent support.","contracts":["No platform runtime assumptions"]},{"id":"hooks","layer":"transport","name":"Platform Hooks","kind":"hook","paths":["n_hooks.c"],"summary":"Registration and invocation of memory, time, mutex, debug, transaction, serial, I2C, and JSON transaction callbacks.","contracts":["Platform boundary","Hook signatures are public contracts"]},{"id":"serial","layer":"transport","name":"Serial Transport","kind":"transport","paths":["n_serial.c"],"summary":"Serial transaction, reset, receive, transmit, and chunking behavior.","contracts":["Uses serial hooks","Protects byte-level request/response flow"]},{"id":"i2c","layer":"transport","name":"I2C Transport","kind":"transport","paths":["n_i2c.c"],"summary":"I2C transaction, reset, query length, receive, transmit, MTU, and chunking behavior.","contracts":["Uses I2C hooks","Owns I2C timing and chunking behavior"]},{"id":"bus","layer":"external","name":"Platform Bus","kind":"external","paths":[],"summary":"UART, USB serial, I2C, or test doubles supplied by the host platform.","contracts":["Implemented outside note-c"]},{"id":"notecard","layer":"external","name":"Notecard","kind":"external","paths":[],"summary":"Device that accepts JSON requests and returns JSON responses.","contracts":["Serial or I2C protocol boundary"]},{"id":"notehub","layer":"external","name":"Notehub","kind":"external","paths":[],"summary":"Cloud service reached by the Notecard; note-c does not communicate with Notehub directly.","contracts":["Indirect dependency only"]}],"edges":[{"from":"apps","to":"api","label":"calls"},{"from":"adapters","to":"api","label":"wraps"},{"from":"tests","to":"api","label":"exercises"},{"from":"api","to":"request","label":"request APIs"},{"from":"api","to":"json","label":"J helpers"},{"from":"api","to":"hooks","label":"hook registration"},{"from":"helpers","to":"request","label":"builds requests"},{"from":"request","to":"json","label":"serialize/parse"},{"from":"request","to":"hooks","label":"active interface"},{"from":"request","to":"serial","label":"serial path"},{"from":"request","to":"i2c","label":"I2C path"},{"from":"serial","to":"hooks","label":"serial callbacks"},{"from":"i2c","to":"hooks","label":"I2C callbacks"},{"from":"hooks","to":"bus","label":"platform calls"},{"from":"bus","to":"notecard","label":"bytes"},{"from":"notecard","to":"notehub","label":"syncs"},{"from":"tests","to":"hooks","label":"mocks"},{"from":"tests","to":"serial","label":"transport tests"},{"from":"tests","to":"i2c","label":"transport tests"},{"from":"utilities","to":"request","label":"support"},{"from":"utilities","to":"json","label":"support"}],"hotspots":[{"id":"public-api","title":"Public API and hook compatibility","nodes":["api","hooks"],"updateRule":"Update docs and consider versioning whenever note.h contracts change."},{"id":"transaction-flow","title":"Request lifecycle","nodes":["request","json","serial","i2c"],"updateRule":"Update docs when timeout, retry, serialization, parsing, memory ownership, or active-interface behavior changes."},{"id":"transport-boundary","title":"Transport and platform boundary","nodes":["serial","i2c","hooks","bus"],"updateRule":"Update docs when byte framing, chunking, MTU, reset, or hook invocation semantics change."},{"id":"adapter-impact","title":"Adapter impact","nodes":["adapters","api","hooks"],"updateRule":"Update docs when note-arduino, note-zephyr, note-espidf, POSIX, or other adapters need coordinated changes."}],"updateTriggers":["Changes to note.h public APIs, typedefs, constants, or hook signatures.","Changes to request lifecycle, timeout, retry, memory ownership, or response handling.","Changes to serial/I2C framing, chunking, transmit, receive, reset, or MTU behavior.","Changes to JSON representation or helper semantics.","Changes to adapter expectations, build/test strategy, release strategy, or versioning."],"filesToUpdateTogether":["ARCHITECTURE.md","docs/architecture/architecture.json","docs/architecture/architecture.html","docs/architecture/decisions/*.md when a durable design decision changes"]}; const positions = { - apps: [210, 46], adapters: [455, 46], tests: [700, 46], - api: [455, 182], - helpers: [180, 318], request: [395, 318], json: [610, 318], utilities: [825, 318], - serial: [285, 468], hooks: [500, 468], i2c: [715, 468], - bus: [285, 606], notecard: [500, 606], notehub: [715, 606] + apps: [210, 58], adapters: [455, 58], tests: [700, 58], + api: [455, 238], + helpers: [180, 428], request: [395, 428], json: [610, 428], utilities: [825, 428], + serial: [285, 650], hooks: [500, 650], i2c: [715, 650], + bus: [285, 852], notecard: [500, 852], notehub: [715, 852] }; - const layerTops = { consumers: 24, api: 160, core: 296, transport: 446, external: 584 }; + const layerTops = { consumers: 32, api: 212, core: 402, transport: 624, external: 826 }; const viewFilters = { all: null, runtime: new Set(["apps","adapters","api","request","json","serial","i2c","hooks","bus","notecard","notehub"]), From e0091ee9010e53b51e9d1c77f3ef36489e7847a4 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Thu, 21 May 2026 15:30:17 +0000 Subject: [PATCH 06/36] Route same-row graph edges around nodes --- docs/architecture/architecture.html | 45 ++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/docs/architecture/architecture.html b/docs/architecture/architecture.html index aa10fab6..a976b83d 100644 --- a/docs/architecture/architecture.html +++ b/docs/architecture/architecture.html @@ -418,31 +418,62 @@

note-c Architecture Map

}); } + const nodeWidth = 170; + const nodeCenterX = nodeWidth / 2; + const nodeCenterY = 38; + function center(id) { const p = positions[id]; - return [p[0] + 85, p[1] + 38]; + return [p[0] + nodeCenterX, p[1] + nodeCenterY]; + } + + function sameRowPath(edge) { + const from = positions[edge.from]; + const to = positions[edge.to]; + const fromRight = from[0] + nodeWidth; + const toRight = to[0] + nodeWidth; + const leftToRight = from[0] < to[0]; + const startX = leftToRight ? fromRight : from[0]; + const endX = leftToRight ? to[0] : toRight; + const y = from[1] + nodeCenterY; + const arcY = y - 46; + return { + d: "M " + startX + " " + y + " C " + startX + " " + arcY + ", " + endX + " " + arcY + ", " + endX + " " + y, + labelX: (startX + endX) / 2, + labelY: arcY - 8 + }; + } + + function defaultPath(edge) { + const a = center(edge.from); + const b = center(edge.to); + const midY = (a[1] + b[1]) / 2; + return { + d: "M " + a[0] + " " + a[1] + " C " + a[0] + " " + midY + ", " + b[0] + " " + midY + ", " + b[0] + " " + b[1], + labelX: (a[0] + b[0]) / 2, + labelY: midY - 6 + }; } function renderEdges() { edgeLayer.innerHTML = ""; architecture.edges.forEach((edge, i) => { - const a = center(edge.from); - const b = center(edge.to); - const midY = (a[1] + b[1]) / 2; + const sameRow = positions[edge.from][1] === positions[edge.to][1]; + const geometry = sameRow ? sameRowPath(edge) : defaultPath(edge); const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); path.setAttribute("id", "edge-" + i); path.setAttribute("class", "edge"); path.dataset.from = edge.from; path.dataset.to = edge.to; - path.setAttribute("d", "M " + a[0] + " " + a[1] + " C " + a[0] + " " + midY + ", " + b[0] + " " + midY + ", " + b[0] + " " + b[1]); + path.setAttribute("d", geometry.d); edgeLayer.appendChild(path); const label = document.createElementNS("http://www.w3.org/2000/svg", "text"); label.setAttribute("class", "edge-label"); label.dataset.from = edge.from; label.dataset.to = edge.to; - label.setAttribute("x", (a[0] + b[0]) / 2); - label.setAttribute("y", midY - 6); + label.setAttribute("x", geometry.labelX); + label.setAttribute("y", geometry.labelY); label.setAttribute("text-anchor", "middle"); label.textContent = edge.label; edgeLayer.appendChild(label); From 1b66d27245f808f47e34b7016b5c4500e5a7eeaa Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Thu, 21 May 2026 15:37:00 +0000 Subject: [PATCH 07/36] Anchor graph edges to node boundaries --- docs/architecture/architecture.html | 44 ++++++++++++++++++----------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/docs/architecture/architecture.html b/docs/architecture/architecture.html index a976b83d..dd23c5bf 100644 --- a/docs/architecture/architecture.html +++ b/docs/architecture/architecture.html @@ -419,23 +419,28 @@

note-c Architecture Map

} const nodeWidth = 170; - const nodeCenterX = nodeWidth / 2; - const nodeCenterY = 38; - function center(id) { + function nodeBounds(id) { const p = positions[id]; - return [p[0] + nodeCenterX, p[1] + nodeCenterY]; + const el = document.getElementById("node-" + id); + const height = el ? el.offsetHeight : 76; + return { + left: p[0], + right: p[0] + nodeWidth, + top: p[1], + bottom: p[1] + height, + centerX: p[0] + (nodeWidth / 2), + centerY: p[1] + (height / 2) + }; } function sameRowPath(edge) { - const from = positions[edge.from]; - const to = positions[edge.to]; - const fromRight = from[0] + nodeWidth; - const toRight = to[0] + nodeWidth; - const leftToRight = from[0] < to[0]; - const startX = leftToRight ? fromRight : from[0]; - const endX = leftToRight ? to[0] : toRight; - const y = from[1] + nodeCenterY; + const from = nodeBounds(edge.from); + const to = nodeBounds(edge.to); + const leftToRight = from.left < to.left; + const startX = leftToRight ? from.right : from.left; + const endX = leftToRight ? to.left : to.right; + const y = from.centerY; const arcY = y - 46; return { d: "M " + startX + " " + y + " C " + startX + " " + arcY + ", " + endX + " " + arcY + ", " + endX + " " + y, @@ -445,12 +450,17 @@

note-c Architecture Map

} function defaultPath(edge) { - const a = center(edge.from); - const b = center(edge.to); - const midY = (a[1] + b[1]) / 2; + const from = nodeBounds(edge.from); + const to = nodeBounds(edge.to); + const down = from.top < to.top; + const startX = from.centerX; + const startY = down ? from.bottom : from.top; + const endX = to.centerX; + const endY = down ? to.top : to.bottom; + const midY = (startY + endY) / 2; return { - d: "M " + a[0] + " " + a[1] + " C " + a[0] + " " + midY + ", " + b[0] + " " + midY + ", " + b[0] + " " + b[1], - labelX: (a[0] + b[0]) / 2, + d: "M " + startX + " " + startY + " C " + startX + " " + midY + ", " + endX + " " + midY + ", " + endX + " " + endY, + labelX: (startX + endX) / 2, labelY: midY - 6 }; } From b50e14c4fc3d0b7804f585e3ed760c5e86f26fcb Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Thu, 21 May 2026 15:41:35 +0000 Subject: [PATCH 08/36] Simplify graph node labels --- docs/architecture/architecture.html | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/architecture/architecture.html b/docs/architecture/architecture.html index dd23c5bf..6c41b851 100644 --- a/docs/architecture/architecture.html +++ b/docs/architecture/architecture.html @@ -181,7 +181,7 @@ .node { position: absolute; width: 170px; - min-height: 76px; + min-height: 52px; padding: 10px 11px; border: 1px solid var(--line); border-top: 5px solid var(--blue); @@ -206,17 +206,13 @@ .node.test { border-top-color: #4b5563; } .node h3 { font-size: 14px; - margin-bottom: 4px; - } - .node p { - color: var(--muted); - font-size: 12px; + margin-bottom: 0; } .paths { display: flex; flex-wrap: wrap; gap: 5px; - margin-top: 8px; + margin-top: 7px; } code { display: inline-block; @@ -412,7 +408,7 @@

note-c Architecture Map

div.style.left = pos[0] + "px"; div.style.top = pos[1] + "px"; const pathHtml = (node.paths || []).slice(0, 3).map(path => "" + path + "").join(""); - div.innerHTML = "

" + node.name + "

" + node.summary + "

" + pathHtml + "
"; + div.innerHTML = "

" + node.name + "

" + pathHtml + "
"; div.addEventListener("click", () => selectNode(node.id)); map.appendChild(div); }); From 3a20f72e0e5eb968bf4d14407b9844ab141620ef Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Thu, 21 May 2026 15:49:16 +0000 Subject: [PATCH 09/36] Widen architecture map layout --- docs/architecture/architecture.html | 78 ++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/docs/architecture/architecture.html b/docs/architecture/architecture.html index 6c41b851..5a4e6be0 100644 --- a/docs/architecture/architecture.html +++ b/docs/architecture/architecture.html @@ -20,7 +20,7 @@ --red: #b42318; --violet: #6750a4; --shadow: 0 14px 32px rgba(23, 32, 38, 0.12); - --map-scale: 0.69; + --map-scale: 0.76; } * { box-sizing: border-box; } body { @@ -65,10 +65,30 @@ } main { display: grid; - grid-template-columns: 220px 1fr 280px; + grid-template-columns: 1fr 280px; + grid-template-areas: + "map details" + "support details"; gap: 16px; padding: 16px; - height: calc(100vh - 92px); + min-height: calc(100vh - 92px); + align-items: start; + } + .supporting { + grid-area: support; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0; + } + .supporting .support-panel + .support-panel { + border-left: 1px solid var(--line); + } + .supporting .panel-body { + max-height: 220px; + } + .details { + grid-area: details; + height: calc(100vh - 124px); min-height: 740px; } aside, .map-wrap, .details { @@ -81,6 +101,9 @@ display: flex; flex-direction: column; } + .supporting { + display: grid; + } .panel-head { padding: 14px 15px; border-bottom: 1px solid var(--line); @@ -126,6 +149,7 @@ .dot.external { background: var(--amber); } .dot.test { background: #4b5563; } .map-wrap { + grid-area: map; position: relative; min-width: 0; overflow: auto; @@ -137,15 +161,15 @@ } .map { position: relative; - width: 800px; - height: 690px; + width: 1064px; + height: 760px; margin: 0 auto; } .map-canvas { position: absolute; left: 0; top: 0; - width: 1160px; + width: 1400px; height: 1000px; transform: scale(var(--map-scale)); transform-origin: left top; @@ -243,7 +267,7 @@ } .edge.dimmed { opacity: 0.12; } .edge-label { - font-size: 11px; + font-size: 12px; fill: #4e5d68; paint-order: stroke; stroke: #fff; @@ -314,26 +338,30 @@

note-c Architecture Map

-
+ + From 2513cd6ded9a43b2247851f691ab779c878b16e7 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Thu, 21 May 2026 18:51:45 +0000 Subject: [PATCH 26/36] Move legend to top strip --- docs/architecture/architecture.html | 77 +++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/docs/architecture/architecture.html b/docs/architecture/architecture.html index 4a088441..22fc521e 100644 --- a/docs/architecture/architecture.html +++ b/docs/architecture/architecture.html @@ -67,21 +67,27 @@ display: grid; grid-template-columns: 1fr 280px; grid-template-areas: + "legend legend" "map reference"; - gap: 16px; + gap: 10px 16px; padding: 16px; min-height: calc(100vh - 92px); align-items: start; } + .legend-strip { + grid-area: legend; + display: flex; + align-items: center; + gap: 18px; + min-height: 34px; + padding: 6px 12px; + } .reference { grid-area: reference; - height: calc(100vh - 124px); - min-height: 740px; - } - .reference .support-panel + .support-panel { - border-top: 1px solid var(--line); + height: 760px; + min-height: 0; } - aside, .map-wrap { + aside, .map-wrap, .legend-strip { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; @@ -121,6 +127,39 @@ background: var(--surface-2); border-color: var(--line); } + .legend-strip .legend-item { + display: inline-flex; + align-items: center; + gap: 5px; + padding: 0; + font-size: 11px; + line-height: 1.2; + white-space: nowrap; + } + .legend-strip .dot { + width: 8px; + height: 8px; + margin-top: 0; + flex: 0 0 auto; + } + .legend-strip strong { + font-size: 11px; + font-weight: 650; + } + .legend-strip br, + .legend-strip .muted { + display: none; + } + .hotspot-panel { + display: flex; + flex: 1 1 auto; + min-height: 0; + flex-direction: column; + } + .hotspot-panel .panel-body { + flex: 1 1 auto; + min-height: 0; + } .dot { width: 12px; height: 12px; @@ -379,21 +418,17 @@

note-c Architecture Map

-
+ diff --git a/docs/architecture/embed-architecture-json.mjs b/docs/architecture/embed-architecture-json.mjs new file mode 100644 index 00000000..67dae385 --- /dev/null +++ b/docs/architecture/embed-architecture-json.mjs @@ -0,0 +1,21 @@ +import { readFile, writeFile } from "node:fs/promises"; + +const htmlPath = new URL("./architecture.html", import.meta.url); +const jsonPath = new URL("./architecture.json", import.meta.url); + +const html = await readFile(htmlPath, "utf8"); +const architecture = JSON.parse(await readFile(jsonPath, "utf8")); +const embeddedJson = JSON.stringify(architecture); + +const architectureDataBlock = /" +); + +await writeFile(htmlPath, nextHtml); From e0e819d698a92b558f4480baaad64f93e1ba53de Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Fri, 22 May 2026 12:24:49 +0000 Subject: [PATCH 33/36] Check architecture HTML data drift in CI --- .github/workflows/ci.yml | 12 ++++++++++++ docs/architecture/README.md | 2 ++ 2 files changed, 14 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 207dc3ef..618bab62 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,6 +68,18 @@ jobs: name: note_c_ci_image path: /tmp/note_c_ci_image.tar + check_architecture_docs: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check embedded architecture graph data + run: | + node docs/architecture/embed-architecture-json.mjs + git diff --exit-code docs/architecture/architecture.html + build_docs: runs-on: ubuntu-latest if: ${{ always() }} diff --git a/docs/architecture/README.md b/docs/architecture/README.md index c28c1b1e..fa41e7a4 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -45,6 +45,8 @@ Keep `../../ARCHITECTURE.md`, `architecture.html`, and `architecture.json` synch node docs/architecture/embed-architecture-json.mjs ``` +The CI pipeline runs the same embed script and fails if `docs/architecture/architecture.html` changes afterward. Treat `architecture.json` as the hand-edited graph source and commit the refreshed HTML artifact with it. + Architecture docs should not become: - Full API reference. From 27ae7bdad5f2478587eb47ce26165738c64c8efc Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields (OpenClaw)" Date: Fri, 22 May 2026 14:09:15 +0000 Subject: [PATCH 34/36] Remove architecture hotspot modals --- docs/architecture/architecture.html | 13 +++++-------- docs/architecture/architecture.json | 4 ++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/architecture/architecture.html b/docs/architecture/architecture.html index 19336318..6b50dde7 100644 --- a/docs/architecture/architecture.html +++ b/docs/architecture/architecture.html @@ -471,7 +471,7 @@

Details

- + +