@wairon/cli 5.1.1-dev.102 → 5.1.1-dev.104

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,120 @@
1
+ # wairon — Language Bindings
2
+
3
+ > The [Architecture Standard](architecture.md) is language-neutral: it prescribes
4
+ > *strategies* (e.g. "wait-free reads / in-order serialized writes"), not
5
+ > primitives. This appendix maps those strategies onto concrete primitives per
6
+ > language. The structural model (blocks, patterns, `owns`/`dependsOn`, layering)
7
+ > is identical everywhere — only the realization below differs.
8
+
9
+ ---
10
+
11
+ ## Structural mapping
12
+
13
+ The model assumes a class-with-methods style and method-only interfaces. Every
14
+ mainstream structured language expresses this:
15
+
16
+ | Concept | Rust | Go | TypeScript / Java / C# / Kotlin | Python |
17
+ |---|---|---|---|---|
18
+ | "class" (component) | `struct` + `impl` | `struct` + methods | `class` | `class` |
19
+ | module of functions (an Orchestrator) | closures capturing the collaborators, or a module of `fn`s taking a `&Deps` | a constructor func returning a struct of closures | TypeScript/Kotlin: a factory `createX(deps)` returning functions closed over `deps`; Java/C#: the class form | a factory returning closures over the collaborators |
20
+ | interface (method contract) | `trait` | `interface` | `interface` | `Protocol` / ABC |
21
+ | port + implementations | trait + impl structs | interface + structs | interface + classes | Protocol + classes |
22
+ | dependency injection | constructor (`new`) | constructor func | constructor | `__init__` |
23
+
24
+ Interfaces are **method contracts only** (no fields). Languages whose interfaces
25
+ can't declare fields (Rust traits, Go interfaces) lose nothing — fields are an
26
+ implementation detail of the concrete type, never part of the L3 contract.
27
+
28
+ **Two forms of an Orchestrator.** An Orchestrator holds only its collaborators, so
29
+ it is realized either as a class whose constructor takes them, or as a **module of
30
+ functions** closed over them: a factory takes the collaborators once and returns
31
+ the component's methods as functions that share them. Functional languages use the
32
+ second form natively — a function that takes the collaborators and returns a
33
+ record or map of functions closed over them, or partial application. In both forms
34
+ the collaborators are the component's `dependsOn` and the functions are its L3
35
+ methods, and nothing at module level holds state between calls: domain state
36
+ belongs in a Store, runtime state in an Actor.
37
+
38
+ ---
39
+
40
+ ## Type mapping
41
+
42
+ Contracts are typed in the neutral grammar of the
43
+ [Architecture Standard](architecture.md#type-expressions-one-neutral-grammar);
44
+ each language spells it with what it has. The TypeScript column is the dialect
45
+ conformance reads code through, and the one an implementer brief carries as
46
+ its `typeMapping`; the others are the idiomatic spellings to follow.
47
+
48
+ | Neutral | TypeScript | Rust | Python | Go | Java / Kotlin / C# |
49
+ |---|---|---|---|---|---|
50
+ | `string` | `string` | `String` | `str` | `string` | `String` / `String` / `string` |
51
+ | `int`, `float` | `number` | `i64`, `f64` (width per L4) | `int`, `float` | `int64`, `float64` | `long`, `double` |
52
+ | `bool` | `boolean` | `bool` | `bool` | `bool` | `boolean` / `Boolean` / `bool` |
53
+ | `bytes` | `Uint8Array` | `Vec<u8>` | `bytes` | `[]byte` | `byte[]` / `ByteArray` / `byte[]` |
54
+ | `date`, `datetime`, `duration` | `string` (ISO 8601) | `chrono` types | `date`, `datetime`, `timedelta` | `time.Time`, `time.Duration` | `java.time` / `DateTime`, `TimeSpan` |
55
+ | `list<T>` | `T[]` | `Vec<T>` | `list[T]` | `[]T` | `List<T>` |
56
+ | `set<T>` | `Set<T>` | `HashSet<T>` | `set[T]` | `map[T]struct{}` | `Set<T>` |
57
+ | `map<K, V>` | `Record<K, V>` | `HashMap<K, V>` | `dict[K, V]` | `map[K]V` | `Map<K, V>` / `Dictionary<K, V>` |
58
+ | `T?` | `T \| null` | `Option<T>` | `T \| None` | `*T` | nullable `T` / `T?` |
59
+ | `A \| B` | `A \| B` | `enum` with payload | `A \| B` | an interface both implement | `sealed` hierarchy |
60
+ | `async T` | `Promise<T>` | `async fn` → `T` | `async def` → `T` | a blocking call or a channel | `CompletableFuture<T>` / `suspend` / `Task<T>` |
61
+ | `result<T, E>` (returns only; `result<void, E>` for `Result<(), E>`) | `T`, throwing `E` on failure (`void` for `result<void, E>`) | `Result<T, E>` (`()` for `void`) | `T`, raising `E` | `(T, error)` | `T` with `throws E` / `Result<T>` / `T`, throwing `E` |
62
+ | enum `E` | `type E = 'a' \| 'b'` | `enum E` | `class E(StrEnum)` | typed `string` constants | `enum E` |
63
+ | named scalar `E` holding `P` | `type E = P` | `struct E(P)` | `E = NewType('E', P)` | `type E P` | a value class / `@JvmInline value class E` / `record struct E(P)` |
64
+ | `any` | `unknown` | `serde_json::Value` | `Any` | `any` | `Object` / `Any` / `object` |
65
+
66
+ ---
67
+
68
+ ## Concurrency strategy → primitives
69
+
70
+ ### Default: wait-free reads / in-order serialized writes
71
+
72
+ Readers load a snapshot reference without blocking; writers are serialized so they
73
+ apply in order; on commit the reference is atomically swapped for all readers;
74
+ values are held by reference so the swap is pointer-only.
75
+
76
+ | Language | Reads | Writes |
77
+ |---|---|---|
78
+ | **Rust** | `ArcSwap<T>::load()` (wait-free) | `Mutex<()>` to serialize, clone-and-`store(Arc::new(...))` |
79
+ | **Go** | `atomic.Value` / `atomic.Pointer[T]` load | `sync.Mutex` to serialize, store new pointer |
80
+ | **Java** | `AtomicReference<T>.get()` | a lock to serialize, `set(newRef)` (or `ConcurrentHashMap` for maps) |
81
+ | **C#** | `Volatile.Read` / `Interlocked` ref read | `lock` to serialize, swap reference |
82
+ | **TypeScript (Node)** | single-threaded event loop — a plain reference read | sequential by the event loop; for workers use a message-passing queue |
83
+
84
+ ### Single value, simple read-modify-write (counter, flag)
85
+
86
+ | Language | Primitive |
87
+ |---|---|
88
+ | Rust | `AtomicU64::fetch_add` / `compare_exchange` |
89
+ | Go | `atomic.AddInt64` / `atomic.CompareAndSwap` |
90
+ | Java | `AtomicLong.incrementAndGet` |
91
+ | C# | `Interlocked.Increment` / `CompareExchange` |
92
+ | TS (Node) | sequential on the event loop; `Atomics` on a `SharedArrayBuffer` across workers |
93
+
94
+ Prefer the atomic op over a lock for a single value: it is one wait-free
95
+ instruction, totally ordered, and cheaper than a mutex (which is itself built on
96
+ atomics and may incur a syscall + context switch under contention). Use a
97
+ compare-and-set **retry loop** only for a compound update of one location that has
98
+ no single-instruction equivalent — never as a general strategy over composite
99
+ state (it can livelock and wastes cycles).
100
+
101
+ ### Exceptions to the default
102
+
103
+ | Situation | Rust | Go | Java |
104
+ |---|---|---|---|
105
+ | write-heavy large map | `DashMap` (sharded) or `im`/`rpds` (persistent) | sharded `map`+`RWMutex`, or `sync.Map` | `ConcurrentHashMap` |
106
+ | cross-store atomic transaction | DB transaction via the Adapter | DB transaction via the Adapter | DB transaction via the Adapter |
107
+ | single-writer (Actor) state | `ArcSwap` reads, no write lock | `atomic.Pointer`, no mutex | `AtomicReference`, no lock |
108
+ | non-shared / write-once | plain ownership / `OnceCell` | plain field / `sync.Once` | `final` / `OnceCell` equivalent |
109
+
110
+ ---
111
+
112
+ ## Notes
113
+
114
+ - In single-threaded runtimes (Node.js) the concurrency machinery collapses to
115
+ plain references; apply the *strategy* (one writer at a time, readers see a
116
+ consistent snapshot) at the worker/message-queue boundary instead.
117
+ - The zero-copy/reference rule (§11 of the standard) assumes shared references are
118
+ cheap and safe. Where a language copies by value, use the language's shared-
119
+ reference type (smart pointer / GC reference) so Indexes hold pointers, not value
120
+ copies.
@@ -0,0 +1,61 @@
1
+ # wairon — Templates
2
+
3
+ A **template** is a reusable agent *shape*: a YAML file with metadata and an
4
+ `instructions` body that is rendered (with the agent's id, name, owned paths,
5
+ etc.) into the agent's brief. Templates are rendering shapes only — they are
6
+ not a source of truth. The agent topology itself is derived from the spec tree.
7
+
8
+ Every brief is composed live (`sdd_get_agent_brief`, `wairon agent brief <id>`)
9
+ from the current tree. The same rendering is written to agent files on disk
10
+ only when the project sets `rules.materializeAgentFiles: true`.
11
+
12
+ Built-in templates live in `src/templates/*.yaml`. Project-local overrides can be
13
+ placed in `.wai/templates/`.
14
+
15
+ ---
16
+
17
+ ## Built-in templates
18
+
19
+ | Template | Used for |
20
+ |----------|----------|
21
+ | `architect` | The `system-architect` meta-agent (maintains the spec tree) |
22
+ | `domain-owner` | A `<subsystem>-owner` or free-standing domain owner |
23
+ | `implementer` | A `<component>-implementer` (writes code 1:1 from a spec) |
24
+ | `reviewer` | A review-focused agent shape |
25
+ | `tester` | A testing-focused agent shape |
26
+ | `guardian` | A meta/guardian agent shape |
27
+
28
+ `agent_resolver` picks the template for each derived agent (`architect`,
29
+ `domain-owner`, `implementer`).
30
+
31
+ ---
32
+
33
+ ## Template format
34
+
35
+ ```yaml
36
+ id: domain-owner
37
+ name: Domain Owner
38
+ version: 1.0.0
39
+ description: Short description.
40
+ requiresOwnedPaths: true
41
+ defaultTags: []
42
+ instructions: |
43
+ You are **{{agentName}}**.
44
+ Owns: {{ownedPaths}}
45
+ ```
46
+
47
+ ### Available render variables
48
+
49
+ `{{agentId}}`, `{{agentName}}`, `{{agentDescription}}`, `{{ownedPaths}}`,
50
+ `{{tags}}`.
51
+
52
+ ---
53
+
54
+ ## SDD skills (not templates)
55
+
56
+ The five SDD skill files in `src/templates/skills/` (`sdd-architect`,
57
+ `sdd-narrative`, `sdd-auditor`, `sdd-implement`, `sdd-delegate`) are different:
58
+ they are copied verbatim (with the
59
+ CLI command substituted) into each target tool's `skills/` directory by
60
+ `wairon skills install` and `wairon generate`. They drive the spec-driven
61
+ workflow in-session rather than rendering an agent file.
package/docs/vision.md ADDED
@@ -0,0 +1,59 @@
1
+ # wairon — Vision
2
+
3
+ > Long-term product direction. Aspirational; implementation is phased
4
+ > (see [roadmap.md](roadmap.md)).
5
+
6
+ ---
7
+
8
+ ## North star
9
+
10
+ wairon makes **architecture itself the interface** between humans and AI coding
11
+ tools. You describe a system once as a validated spec tree; from it, wairon
12
+ derives the agents that build it and enforces the boundaries they must respect —
13
+ so AI-generated code is structurally correct and conformant by construction, not
14
+ by review.
15
+
16
+ The differentiator is not "spec-driven development" in general (many tools do the
17
+ prose-spec → plan → tasks loop). It is the **architecture-conformance engine**:
18
+ typed component stereotypes with enforced dependency rules, contract↔
19
+ implementation symmetry, narrative-to-code mapping, and cycle detection — checked
20
+ as a gate before code is written.
21
+
22
+ ---
23
+
24
+ ## Principles that don't change
25
+
26
+ - **Specs are the source of truth.** Agents, boundaries, and conformance are
27
+ derived from `.wai/specs/`. Generated files are outputs.
28
+ - **wairon equips, it does not orchestrate.** It produces native subagents,
29
+ installs skills, and exposes MCP tools. The host AI tool (Claude Code, Gemini
30
+ CLI, …) runs the session and spawns its own subagents.
31
+ - **Optional, then strict.** A project opts in by creating a spec tree. Once
32
+ enabled, the workflow is enforced: design before code, spec is law,
33
+ human-in-the-loop.
34
+ - **`.wai/` boundary, file-based, offline core.** All state is human-readable
35
+ files under `.wai/`; no database, and the core workflow needs no daemon or
36
+ network. Hosting (`wairon serve`) is an opt-in server over the same files.
37
+
38
+ ---
39
+
40
+ ## Where it goes
41
+
42
+ 1. **Deeper conformance.** Glob-aware ownership, richer stereotype rules,
43
+ actionable remediation — the engine becomes a true architecture linter for AI
44
+ codegen.
45
+ 2. **Adoption without greenfield.** Derive a draft spec tree from existing code
46
+ so teams can apply conformance to what they already have.
47
+ 3. **CI as the gate.** `wairon validate --ci` in PR checks, with conformance
48
+ diffs reported on the change.
49
+ 4. **Org scale.** Shared standards and template libraries across repos.
50
+
51
+ ---
52
+
53
+ ## What was deliberately dropped
54
+
55
+ An earlier vision positioned wairon as a local AI **orchestration hub** —
56
+ spawning sessions, multi-model pipelines, git worktrees, a session wrapper. That
57
+ fought the host tools (which now have native subagents and worktrees) and spread
58
+ the product thin. wairon instead does one thing well: turn a validated spec tree
59
+ into a conformance gate plus the topology and skills a host AI tool consumes.
@@ -0,0 +1,74 @@
1
+ # Wairon Feature Request: Hosted, Multi-Tenant MCP Server
2
+
3
+ **Requested by:** Robbe Vrijenhoek (Appenser / wairon wrapper project)
4
+ **Date:** 2026-07-04
5
+ **Context:** Building Appenser, a Make.com doctrine wrapper on wairon. Working entirely from within Langdock (an enterprise AI platform) rather than a local Claude Code / Gemini CLI setup surfaced several gaps between wairon's current (local, CLI-first) execution model and a hosted, multi-tenant, MCP-only usage pattern. This document summarizes the capabilities we'd like wairon to support.
6
+
7
+ ---
8
+
9
+ ## 1. Hosted, multi-tenant MCP server mode
10
+
11
+ **Problem today:** `wairon mcp serve` is documented as a local process, `stdio`-attached to a single coding tool working against a single on-disk repo. There's no mode for running wairon as a standing service that multiple clients/projects can connect to remotely.
12
+
13
+ **Request:** A `wairon mcp serve --http` (or similar) mode that:
14
+ - Exposes the existing `sdd_*` tool surface over **streamable HTTP**, not just stdio, so it can be reached by remote MCP clients (e.g. a Langdock custom agent) rather than only a co-located CLI tool.
15
+ - Can be packaged as a **Docker image** for self-hosting (e.g. on GCP, or any container platform) — a self-contained binary with an HTTP wrapper, no external dependencies required for a basic deployment.
16
+ - Persists spec trees to a **local/mounted filesystem** (`/data/projects/<project-id>/.wai/...`) so wairon itself is the source of truth and durability layer — not dependent on any particular git host to function.
17
+
18
+ **Why:** Removes the need to run wairon inside a sandboxed AI-tool shell (fragile, non-persistent, no real network access in many AI platform sandboxes) and instead lets any MCP-capable client connect to a real, durable, always-on wairon instance.
19
+
20
+ ---
21
+
22
+ ## 2. Multi-project support behind a single MCP endpoint, scoped by authentication (not by client-supplied parameters)
23
+
24
+ **Problem today:** No multi-tenancy model exists. A hosted instance needs to serve many independent spec trees ("projects"/workspaces) without one client being able to access another's data.
25
+
26
+ **Request:**
27
+ - A single running wairon MCP endpoint should be able to serve **multiple projects**, each with its own isolated `.wai/` spec tree.
28
+ - **Project scope must be derived from the authenticated session/token, not from a client-supplied parameter.** I.e., an API key/OAuth token issued for Project A must be server-side bound to Project A; the server rejects or ignores any attempt by that token's calls to reach another project's tree. A `project` selector parameter is acceptable as a convenience for tokens explicitly authorized for multiple projects, but must never itself be the authorization mechanism.
29
+ - Explicitly **not requesting** a model where a new MCP server process is spawned per project — that adds operational complexity (process/port lifecycle, discovery) without a corresponding benefit, since MCP tool calls can be made stateless per-request against a shared service.
30
+
31
+ **Why:** This is the standard, defensible multi-tenant pattern (auth-derived scope) and avoids both the operational cost of per-project server spawning and the security risk of trusting client-declared scope.
32
+
33
+ ---
34
+
35
+ ## 3. Authentication layer for the hosted MCP server
36
+
37
+ **Problem today:** No auth story exists for a networked MCP server (local `stdio` mode has no need for one).
38
+
39
+ **Request:** Support at least one straightforward auth mechanism suitable for internal/company deployments as a v1 — e.g. static API keys mapped to authorized project ID(s) via a config file or injected secret — with a clear upgrade path to OIDC/OAuth for broader or external exposure later. Full enterprise identity federation is **not** a v1 requirement; a defensible internal-tool-grade auth model is sufficient to start.
40
+
41
+ ---
42
+
43
+ ## 4. Privileged, commit-scoped `sdd_init` and `sdd_lock` MCP tools, with re-validation enforced at merge time
44
+
45
+ **Problem today:** `wairon init` and `wairon lock` are CLI-only, unavailable via MCP. If exposed via MCP naively, a "lock" recorded once could be trusted even after the underlying branch/commit has since changed — a stale-approval / time-of-check-to-time-of-use gap.
46
+
47
+ **Request:**
48
+ - Expose `sdd_init` and `sdd_lock` as MCP tools, but treat them as **privileged** relative to the rest of the `sdd_*` surface (e.g. only callable by a specifically authorized identity/role, such as a hosting/orchestration layer rather than every ordinary editing session).
49
+ - `sdd_lock` must:
50
+ 1. Run `wairon validate` fresh, at the current state of the spec tree.
51
+ 2. Only if validation passes, write a **lock record scoped to the exact commit/state it validated** (e.g. `{ stateId/commitSha, lockedAt, validationResult }`), not a free-floating "this project is locked" flag.
52
+ 3. **Never perform a merge to any main/production branch or state itself.** At most, it should be able to open/update a pull request (if git-backed) or mark a change-set as "ready," leaving the actual promotion action to a separate, human-gated step.
53
+ - Whatever mechanism promotes locked changes to the canonical/production state (a git merge, or an equivalent "promote" action in wairon's own native storage) must **re-check that the lock record's scoped commit/state ID matches the current state exactly** before allowing promotion. Any change made after locking must invalidate the lock automatically (by the state ID no longer matching), forcing re-validation and re-locking — not by requiring anyone to remember to manually invalidate a stale lock.
54
+
55
+ **Why:** This closes a real correctness/safety gap: without commit-scoped lock validity plus a mandatory re-check at promotion time, it's possible to lock a valid spec tree, make further (possibly broken) changes, and still merge/promote on the strength of the earlier, now-stale lock.
56
+
57
+ ---
58
+
59
+ ## 5. (Lower priority / later) Pluggable persistence & sync backends
60
+
61
+ **Problem today:** If/when git-backed persistence is desired, wairon currently has no first-class model for it, and we don't want to hard-couple wairon's core storage model to one git host (GitHub) on day one — GitLab, other git hosts, or entirely non-git backends (e.g. Notion) may be desirable later.
62
+
63
+ **Request:** Treat wairon's own native on-disk (or hosted-instance-managed) storage as the primary source of truth, and treat git-host integration (GitHub, GitLab, etc.) or other external sync targets as **optional export/mirror/sync features** layered on top — e.g. a future `wairon sync --git <remote>` — rather than a required dependency for wairon to function at all.
64
+
65
+ **Why:** Keeps wairon host-agnostic and avoids picking a single vendor's collaboration model (PRs, branch protection, etc.) as the only supported workflow.
66
+
67
+ ---
68
+
69
+ ## Explicitly out of scope / not being requested
70
+
71
+ - Per-project MCP server process spawning (see #2).
72
+ - A `wairon generate --target <specific-AI-platform>` "subagent" template for platforms that don't support isolated subagent dispatch the way Claude Code/Gemini CLI do — this pattern is only valuable where the host tool provides genuine context isolation for spawned subagents; generating a redundant role-description file for a platform without that mechanism (which we already read the underlying specs directly) adds no value and was considered and rejected during our own design process.
73
+ - Full enterprise SSO/identity federation as a v1 requirement for the hosted MCP server.
74
+ - `sdd_lock` (or any MCP tool) performing an actual merge/promotion to a production branch/state — this must remain a separately gated action.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wairon/cli",
3
- "version": "5.1.1-dev.102",
3
+ "version": "5.1.1-dev.104",
4
4
  "description": "SYW Waffle AIron — CLI for managing AI coding agent topology across projects",
5
5
  "keywords": [
6
6
  "ai",
@@ -28,7 +28,9 @@
28
28
  "files": [
29
29
  "dist",
30
30
  "schemas",
31
- "README.md"
31
+ "README.md",
32
+ "docs/*.md",
33
+ "docs/standards/**"
32
34
  ],
33
35
  "workspaces": [
34
36
  "sdk"