Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
471 changes: 471 additions & 0 deletions .claude/skills/atlas/SKILL.md

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ Key principles:
| `truffle-bench` (`benchmark/engine`) | Benchmark engine (lib) + CLI (bin): workloads, peer control protocol, v3 reports, suites (RFC 027). `publish = false` |
| `truffle-bench-app` (`benchmark/app/src-tauri`) | Tauri v2 shell of the "truffle bench" desktop app; frontend is `@vibecook/truffle-bench-app` (`benchmark/app`, React + Vite, private). `publish = false` |

Each crate's place in the RFC 012 stack and its domain are declared in `atlas/` or its crate root and graded by Atlas (see "Atlas" below).

## Build & Test

```bash
Expand Down Expand Up @@ -91,6 +93,18 @@ pnpm --filter @vibecook/truffle-bench-app app:dev # the
- **Commit types**: release-please ignores a commit only if *every* file is under `benchmark/` (`exclude-paths`). Hub changes that touch anything else use `chore(bench):`, `ci:`, `build:` or `docs:` — never `feat:`/`fix:`. Library changes the hub needs ship separately as `feat(core):`
- Nightly: `benchmarks.yml` (`suite --profile nightly --pair`); PR: `integration-tests.yml` runs `-p truffle-bench --tests` (`live_pair`)

## Atlas

`atlas/*.atlas` plus `@atlas` comment lines declare what code cannot say about itself: the RFC 012 layer stack, domains, runtime links, contracts, four hot-path flows, dependency rules and RFC decisions. Project Atlas grades each statement against the code. It is not a third living document: every rule and decision cites this file, `docs/`, a README or a comment in the code with a checked `see "file#slug"` (`#L<n>` for a line). Authoring guide: the `atlas` skill.

- **Where**: truffle-napi, truffle-tauri-plugin, truffle-bench and truffle-bench-app end their root `//!` doc (the benchmark crates' `lib.rs`) with their placement; seams and flow steps carry `// @atlas` lines (`grep -rn '@atlas' crates benchmark`). The crates.io crates (truffle-core, truffle, truffle-sidecar) carry no `//!` atlas text, so docs.rs shows none: they, truffle-cli (no crate doc), truffle-core's module tiers, the npm packages (`@vibecook/truffle-bench-app` included) and the directories (`benchmark/schema/` included) are placed in `atlas/layers.atlas` and `atlas/domains.atlas`.
- **New code**: place a new crate, truffle-core module, npm package or top-level directory in a layer and a domain in the same change. A truffle-core module you forget lands in node-api and `mesh` and nothing reports it: `explain` it.
- **Renames**: update every selector that names the code, in `atlas/` and in other code's `@atlas` lines (brace forms like `mod:truffle_core::{node, identity, egress}` hide from grep). `check` must then show 0 DANGLING. Moving the code of a known finding makes it new (the skill's "Known or new").
- **Never weaken a rule to make it pass**: fix the code. Widening an `only` list, adding an `except`, moving a module to another tier or changing what a rule or decision means is the user's call, even when `check` suggests it. `atlas/atlas.baseline.json` is written only by `atlas baseline`, and `atlas baseline` runs only when the user decides to accept today's violations, never to turn the check green.
- **Check** from the repo root after changing crates, modules, packages, dependencies, `atlas/`, or a heading in CLAUDE.md, a README or `docs/` (`see` cites them by slug): `TRUFFLE_SIDECAR_SKIP_DOWNLOAD=1 npm --prefix "${ATLAS:-$HOME/Projects/project100/protos/project-atlas}" run -s atlas -- check "$PWD" --intent "$PWD/atlas"`. It runs `cargo doc` over the workspace (a build, build scripts included); the variable keeps truffle-sidecar's build script offline, as CI's lint job does (`cargo doc` never runs the sidecar). Atlas is a private tool: if `$ATLAS/package.json` is missing (the command exits 254 with no output), skip the check, install nothing, and say so. When builds are off-limits, run the syntax-only check: `ATLAS="${ATLAS:-$HOME/Projects/project100/protos/project-atlas}"; "$ATLAS/node_modules/.bin/tsx" "$ATLAS/packages/engine-intent/src/cli.ts" atlas crates benchmark packages examples`.
- **Reading it**: exit 1 = a new error violation. `atlas/atlas.baseline.json` records the 7 findings kept for the user (listed in the skill), so a clean tree prints them under `VIOLATED · known` and exits 0. Known means per package or module pair: a further import between a pair already listed stays known, so compare each known claim's count with the skill's list. Do not change code, rules or tiers for them unless asked. DANGLING does not fail the check but must be fixed, and a dangling rule, contract or flow named in a decision's `confirmed-by` makes that decision violated (exit 1; for `layered-architecture` and `synced-store`, already known, only DANGLING and the decision's evidence show it): fix the selector.
- **Commits**: an atlas-only change is `docs:` or `chore:`, never `feat:`/`fix:`, which make Release Please cut a release. Staged `@atlas` lines still trigger the pre-commit hook: a staged truffle-napi `src/*.rs`, `Cargo.toml` or `build.rs` runs a release `napi build` (and fails if pnpm is missing); a staged truffle-core `lib.rs`/`node.rs` or truffle `lib.rs`/`Cargo.toml` runs `cargo test -p truffle --doc`; every staged `.rs` gets rustfmt (the skill lists all 7 checks). Never put `@atlas` in a `///` line: rustdoc renders it, and NAPI-RS copies item docs into `index.d.ts`.

## RFCs

RFCs live in `docs/rfcs/`. Key ones:
Expand Down
18 changes: 18 additions & 0 deletions atlas/atlas.baseline.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"schema": "atlas.baseline/1",
"violations": [
"claim:contract:sync-wire/contract/565c34d2",
"claim:decision:layered-architecture/decision/74afec74",
"claim:decision:synced-store/decision/6487f263",
"rule:apps-use-node-api|pkg:cargo/truffle-bench|pkg:cargo/truffle-core",
"rule:apps-use-node-api|pkg:cargo/truffle-cli|pkg:cargo/truffle-core",
"rule:apps-use-node-api|pkg:cargo/truffle-napi|pkg:cargo/truffle-core",
"rule:apps-use-node-api|pkg:cargo/truffle-tauri-plugin|pkg:cargo/truffle-core",
"rule:layers-point-down|mod:rs/truffle_core::network::tailscale::provider|mod:rs/truffle_core::egress",
"rule:layers-point-down|mod:rs/truffle_core::network|mod:rs/truffle_core::egress",
"rule:layers-point-down|mod:rs/truffle_core::transport::websocket|mod:rs/truffle_core::session::hello",
"rule:network-knows-no-upper-layer|mod:rs/truffle_core::network::tailscale::provider|mod:rs/truffle_core::egress",
"rule:network-knows-no-upper-layer|mod:rs/truffle_core::network|mod:rs/truffle_core::egress",
"rule:transport-knows-no-session|mod:rs/truffle_core::transport::websocket|mod:rs/truffle_core::session::hello"
]
}
131 changes: 131 additions & 0 deletions atlas/components.atlas
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Runtime units and how they talk. A link with `via` is a runtime claim: asserted, its `at` anchors must resolve and
// each `witness` literal must occur in their code (comments stripped). A link without `via` is graded against code
// edges. Go, Swift and guest-js files are reachable only by `file:`/`path:` anchors.

component core "truffle-core (in-process library)" kind library {
intent "A Rust host embeds a Node<TailscaleProvider>, which owns its sidecar child and loopback bridge."
contains crate:truffle-core
see "CLAUDE.md#architecture"
}
component sidecar "sidecar-slim (Go child process, tsnet inside)" kind process {
intent "tsnet lifecycle, tailnet dial and listen, peer watch, the RFC 023 serve engine and RFC 026 egress; no envelopes, sessions or subsystems."
contains path:packages/sidecar-slim/, !path:packages/sidecar-slim/cmd/
see "docs/rfcs/012-layered-architecture-redesign.md#36-layers-1-2-bridge--sidecar-internal-to-tailscaleprovider"
}
component cli "truffle (CLI binary)" kind cli {
contains crate:truffle-cli
component daemon "truffle up --foreground, or bare truffle (the TUI): owns the Node" kind daemon {
contains file:crates/truffle-cli/src/daemon/{server, handler}.rs, path:crates/truffle-cli/src/tui/
}
component agent "truffle <command>: a short-lived JSON-RPC client" kind cli {
contains path:crates/truffle-cli/src/commands/, file:crates/truffle-cli/src/daemon/client.rs
}
see "docs/rfcs/013-tui-redesign.md#3-architecture-decision-tui--foreground-daemon"
}
component bench "truffle-bench (the engine library and its CLI: hubs that run and answer workloads, or a pair in one process)" kind library {
contains crate:truffle-bench
see "docs/rfcs/027-benchmark-hub.md#54-hub"
see "docs/rfcs/027-benchmark-hub.md#10-cli"
}
component bench-app "truffle bench (Tauri v2 desktop app: the engine's Hub runs in the app process)" kind app {
contains crate:truffle-bench-app
component bench-ui "React frontend (in the webview)" kind ui { contains pkg:@vibecook/truffle-bench-app }
see "docs/rfcs/027-benchmark-hub.md#111-shell-and-process"
}
component napi "NAPI addon (inside the Node.js or Electron process)" kind native-addon {
contains crate:truffle-napi, pkg:@vibecook/truffle-native
}
component js-sdk "@vibecook/truffle" kind library { contains pkg:@vibecook/truffle }
component react "@vibecook/truffle-react" kind library { contains pkg:@vibecook/truffle-react }
component tauri "Tauri plugin (Rust, in the Tauri app process)" kind plugin {
contains crate:truffle-tauri-plugin
component tauri-guest "guest-js (in the webview)" kind ui-library { contains path:crates/truffle-tauri-plugin/guest-js/ }
}
component swift "Truffle Swift (in-process on iOS and macOS, no sidecar)" kind library {
contains path:apple/Sources/
see "docs/rfcs/024-truffle-swift.md#52-runtime-split-one-api-two-engines"
}
component tailnet "Tailscale control plane, DERP and WireGuard peers" external
component peer "Another truffle node on the tailnet (Rust or Swift)" external
component tailscalekit "TailscaleKit / libtailscale (pinned XCFramework)" external
component host-apps "Other processes on the node's host (served targets, egress clients)" external

core -> sidecar "spawned child; JSON lines: commands on stdin, events on stdout" via spawn {
at mod:truffle_core::network::tailscale::sidecar, mod:truffle_core::network::tailscale::protocol
at file:packages/sidecar-slim/main.go
witness "kill_on_drop"
witness "tsnet:start"
}
sidecar -> core "loopback TCP bridge: TRFF header and session token, then raw bytes" via ipc {
at mod:truffle_core::network::tailscale::{bridge, header}, file:packages/sidecar-slim/main.go
witness "127.0.0.1:0"
witness "0x54524646"
}
core -> peer "peer session: WebSocket /ws on tailnet port 9417, hello v2, then JSON envelopes" via ws {
at mod:truffle_core::transport::websocket, mod:truffle_core::session::hello
witness "/ws"
}
core -> peer "raw tailnet TCP, UDP and app-scoped QUIC (ALPN truffle-raw.{appId})" via port {
at mod:truffle_core::transport::{tcp, quic}, mod:truffle_core::network::tailscale::provider
witness "truffle-raw"
}
core -> sidecar "loopback UDP relay for datagrams and QUIC, HMAC-tokened per binding" via port {
at mod:truffle_core::network::tailscale::provider, file:packages/sidecar-slim/udp_relay.go
witness "TRUFFLE_UDP_REGISTER"
}
swift -> peer "the same session protocol, a second implementation" via ws {
at file:apple/Sources/Truffle/Session/RFC6455FrameTransport.swift
witness "GET /ws HTTP/1.1"
}
sidecar -> tailnet "tsnet.Server: WireGuard tunnels; peers from LocalAPI WatchIPNBus" via port {
at file:packages/sidecar-slim/main.go
witness "WatchIPNBus"
}
swift -> tailscalekit "tailscale_dial and tailscale_listen; LocalAPI WatchIPNBus and WhoIs" via embed {
at file:apple/Sources/TruffleTailscale/TailscaleKitBackend.swift
witness "tailscale_dial"
}
agent -> daemon "JSON-RPC 2.0, one object per line, over a Unix socket or named pipe" via ipc {
at file:crates/truffle-cli/src/daemon/{ipc, protocol}.rs, file:crates/truffle-cli/src/config.rs
witness "truffle.sock"
witness "push_file"
}
agent -> daemon "truffle up, and any command when auto_up is on, re-execs the binary detached as `up --foreground`" via spawn {
at file:crates/truffle-cli/src/commands/up.rs, file:crates/truffle-cli/src/daemon/client.rs
witness "--foreground"
}
tauri-guest -> tauri "invoke plugin:truffle commands; listen to truffle:// events" via ipc {
at file:crates/truffle-tauri-plugin/guest-js/index.ts, mod:truffle_tauri_plugin::events
witness "plugin:truffle|start"
witness "truffle://peer-event"
}
host-apps -> sidecar "RFC 026 egress: loopback SOCKS5, fixed routes, CONNECT proxy" via port {
at file:packages/sidecar-slim/egress.go
witness "127.0.0.1:0"
}
tailnet -> sidecar "HTTP(S) from any tailnet client to a mesh.serve listener" via http {
at file:packages/sidecar-slim/main.go
witness "ListenTLS"
}
sidecar -> host-apps "RFC 023 serve: reverse proxy to a loopback target with Tailscale identity headers" via http {
at file:packages/sidecar-slim/main.go
witness "Tailscale-User-Login"
}
bench -> peer "RFC 027 control protocol: hello, clock, prepare, start and finish, each acked, on namespace \"bench\"" via ws {
at mod:truffle_bench::control
witness "\"prepare\""
witness "\".ack\""
}
bench-ui -> bench-app "invoke the RFC 027 §11.2 commands; hub events on bench://event, run progress on a Channel" via ipc {
at file:benchmark/app/src/api/{api, tauri}.ts, mod:truffle_bench_app::commands
witness "bench://event"
witness "bench_run"
}

js-sdk -> napi "loads the addon in-process: NapiNode, socket handles, event callbacks"
react -> js-sdk "hooks over the mesh node"
napi -> core "binds one Node<TailscaleProvider>"
tauri -> core "binds one Node<TailscaleProvider>"
cli -> core "the daemon owns one Node<TailscaleProvider>"
bench -> core "builds every node with NodeBuilder (one Node<TailscaleProvider> per hub) and drives the workloads on it"
bench-app -> bench "the shell owns one Hub; every run and suite executes in the engine"
38 changes: 38 additions & 0 deletions atlas/contracts.atlas
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Seams with several anchors are declared here. Contracts with one anchor are declared in-code at their trait or
// enum: network-provider (NetworkProvider), envelope-codec (EnvelopeCodec), store-backend (StoreBackend), ft-wire
// (FtMessage) and sync-wire (SyncMessage).

contract transport-traits "Layer 4 transport trait families" {
intent "Framed streams (WebSocket, QUIC), raw byte streams (TCP) and datagrams (UDP); Layer 5 consumes FramedStream."
at sym:truffle_core::transport::{StreamTransport, FramedStream, RawTransport, DatagramTransport}
implemented-by crate:truffle-core
see "docs/rfcs/012-layered-architecture-redesign.md#34-layer-4-transport"
}

contract napi-projection "The key types every binding bridges, as NAPI exports" {
intent "RFC 015's list of types to bridge; each has a Napi-prefixed export in the generated index.d.ts."
at sym:truffle_core::{Peer, NamespacedMessage, FileOffer, FileTransferEvent, TransferResult}
at sym:truffle_core::session::PeerEvent, sym:truffle_core::network::{NodeIdentity, PingResult}
mirror "crates/truffle-napi/index.d.ts#Napi{name}"
note file:crates/truffle-napi/index.d.ts "Generated by NAPI-RS; the pre-commit hook rebuilds it and blocks a commit whose copy is stale."
see "docs/rfcs/015-binding-rewrite.md#3-current-node-api-what-bindings-must-wrap"
see "CLAUDE.md#pre-commit-hook-one-time-setup-per-clone"
}

contract session-wire "Session wire contract: hello v2 and the JSON envelope" {
intent "Both engines speak it verbatim; the wire `from` is never trusted, the receiver stamps the WhoIs-verified id."
at sym:truffle_core::Envelope, sym:truffle_core::session::hello::HelloEnvelope
note file:apple/Sources/Truffle/Wire/Envelope.swift, file:apple/Sources/Truffle/Wire/HelloEnvelope.swift "The Swift mirrors, field for field."
note path:apple/Tests/TruffleTests/Fixtures/ "Shared fixtures, decoded by WireTests.swift and by crates/truffle-core/tests/interop_fixtures.rs."
see "docs/rfcs/024-truffle-swift.md#81-session-protocol-as-shipped"
see "apple/README.md#wire-compatibility-rfc-024-8"
}

contract bench-app-types "The RFC 027 §7 fixture types, mirrored by hand in TypeScript" {
intent "Rust is the source of truth (benchmark/schema is generated from it); app/src/api/types.ts is hand-written, and fixtures.test.ts type-checks every fixture against it."
at sym:truffle_bench::types::{HubEvent, NodeState, Progress, RunSummary, AppInfo, Settings, BenchPeer, PeerProbe, SuiteProfile}
at sym:truffle_bench::params::WorkloadParams, sym:truffle_bench::report::RunReport, sym:truffle_bench::error::AppError
mirror "benchmark/app/src/api/types.ts#{name}"
see "docs/rfcs/027-benchmark-hub.md#7-types-shared-with-the-app"
see "benchmark/README.md#reports"
}
Loading
Loading