Releases: ChanMeng666/archlang
Release list
v1.18.0
Two behaviour improvements to arch suggest (suggestTopology), requested by the downstream
ArchCanvas product, which persists a chosen candidate's insertText back into .arch source. Both
are unconditional — per ADR 0005 suggestions
are deterministic data, and the new behaviour is strictly more correct, so there is no opt-in flag.
The public Suggestion / SuggestionCandidate types are unchanged; only the string a candidate
carries (and, for one fault, candidate order) changes.
Changed
- Candidates reference walls only by a STABLE ref. A candidate's
insertTextused to be able to
name a wall by its positional auto-id (e.g.door on partition_3 at 50%), which re-indexes
silently when a later edit inserts an earlier same-category wall — corrupting any persisted
suggestion. Each candidate now composes its placement as the first available of: an author-declared
wall id (on <id>), a unique wall category (on <category>, valid iff exactly one wall carries
it), or absolute coordinates (at (x, y), which name no wall — the compiler's nearest-wall
hosting binds the intended one). A positional auto-id is never emitted. Applies to all four
builders (entrance, unreachable-room, bedroom-window, bath-via-bedroom). - A private unreachable room prefers reconnecting inward. For
W_ROOM_UNREACHABLEon a private
room (bedroom or wet room), interior candidates that reconnect to a space already reaching the
entrance now rank above exterior (new-outside-door) candidates, regardless of run length; within
each group the existing longest-free-run order is kept. Non-private rooms keep the pure geometric
order.W_NO_ENTRANCE(exterior-first by design),W_BATH_VIA_BEDROOM(already interior-preferred),
andW_BEDROOM_NO_WINDOW(windows are exterior-only) are unchanged.
Internal
RWallcarries an internal_idAuthoredmarker (set inresolvefromassignIds' knowledge of
whether the id was author-declared;_-prefixed, never serialized into the Scene/exports), so
suggestTopologycan tell an authored id from an assigned positional one.
v1.17.0
Agent-CLI round: the arch CLI audited against the 7 Principles for Agent-Friendly
CLIs rubric and hardened where it fell short.
The audit's good news is that the foundations already held — zero interactive prompts, zero ANSI
colour, --json almost everywhere, a documented 0/2/1/3 exit contract, a uniform stdin - seam,
and JSON diagnostics that already carry their own fixes. What it found was one blocker (a CLI an
agent literally could not ask for help), a parser that silently swallowed typo'd flags as
filenames, a fix that clobbered your source with no preview and no recovery, and reads that
had no way to be narrowed. All four are closed here. The language is untouched; compile() stays
pure and its default output byte-identical.
Added
- Per-command help — the blocker.
arch <cmd> --helpandarch help <cmd>now print help.
Before this,--helpafter a verb fell throughparseArgsinto the positionals and was read as a
filename (cannot read --help), so the standard two-hop probe an agent uses to learn a CLI —
top-level help, then subcommand help — was broken at the second hop. - The manifest now carries worked
examples[]per command (a required field), and a new
src/cli/help.tsrenders both the top-level and the per-command help from the manifest.
The hand-maintainedHELPstring — a second, un-drift-tested source of truth for the command list
— is gone, so help can no longer advertise a flag a command doesn't take. arch --version.arch fix --backup— saves the original bytes to<file>.bakbefore rewriting in place
(opt-in, so no.baklitter by default), andfixnow prints the unified diff it would write
to stderr,--dry-runincluded.fixrewrites your source; it should be previewable and
reversible.- Bounded reads (so one big plan can't blow an agent's context window):
arch describe --select <keys>/--room <ids>,arch lint|validate --code <CODE>/
--severity <sev>, andarch context --section <spec|workflow|cli|errors>— the error catalog
alone drops the bundle from 60,187 → 13,161 bytes. unifiedDiffmoves fromdataset/into the pure core assrc/unified-diff.ts(zero-dep,
deterministic);dataset/diff.tsre-exports it.
Changed
- An unrecognized flag or verb is now a usage error (exit 3), not a silently-swallowed filename.
AFLAG_KEYSparse table replaces the old if/else chain and is bidirectionally drift-tested
against the manifest, so the parser, the help, and the docs cannot disagree about what a command
accepts.arch lint --jsnnow exits 3 withdid you mean \--json`?and ausage:echo;arch complesuggestscompile`. - Human-mode diagnostics print the catalog's
= fix:line. JSON mode already carried it; a
human (or an agent reading stderr) previously had to make a second call toarch explain <CODE>. arch lint --profile <bogus>routes throughusageErrorlike every other bad-usage path (it used
to return a bare3with an ad-hoc, prefix-less message).arch mdvalidates-fthrough the sharedparseFormatinstead of a hand-rolled check, so an
unknown format gives the same error everywhere.- Bare
archprints its help to stderr (exit code 3, unchanged) rather than stdout — a missing
command is a usage error, and its output shouldn't pollute a pipe. - Previously-ignored misplaced flags (e.g.
arch describe --strict, on a command that takes no such
flag) now exit 3 instead of being ignored.
Invariants pinned by tests
- A display filter never changes gating.
--code/--severity/--select/--roomfilter
what is shown; the exit code andokare computed from the unfiltered diagnostic set, so
lint --code W_FOOon a plan failing for a different reason still fails. - The
context --sectionsplitter is welded to its generator by a test that regenerates
llms-full.txtin memory and asserts the split — a format change breaks loudly instead of
silently slicing garbage.
v1.16.0
Downstream-driven round: ArchCanvas's archlang-1.15 adoption surfaced two upstream gaps its own
ship gate + topology fixer had already filled locally, so those capabilities move upstream as
advisory data and the generated agent docs are re-pointed to teach the v1.13 placement sugar
where models actually imitate it — the worked examples. Core stays zero runtime dependencies; the
default SVG output is byte-identical throughout.
Added
-
suggestTopologygains two connectivity-fault kinds —Suggestion.codewidens 2 → 4 to
W_ROOM_UNREACHABLE | W_BEDROOM_NO_WINDOW | W_NO_ENTRANCE | W_BATH_VIA_BEDROOM. Both new builders
are ported from capabilities proven in ArchCanvas's production topology fixer and each mirrors the
semantics of the matchingarch lintrule so a suggestion fires iff the lint fires:W_NO_ENTRANCE— fires when the plan has an exterior wall but no entrance
(access.hasEntrance === false). Emitsdoor on <wall> at <pct>% width 900candidates on the
longest opening-free exterior run of an entrance-suitable room (not a bedroom, not a wet room),
falling back to the remaining rooms only when no suitable room touches an exterior wall; the
rationale names the room and that this creates the building's entrance.W_BATH_VIA_BEDROOM— reuses the two-BFS pattern from the reachability lint (reach-all vs
reach-excluding-bedrooms) to find a wet room reachable only through a bedroom, and suggests a
door onto a neighbour that itself has a bedroom-free route (non-bedroom neighbours preferred over
an exterior-wall fallback regardless of run length — reconnecting to circulation is the real fix).
One suggestion per affected wet room.
Both stay ADR 0005-compliant (facts and lint, not an architect):
deterministic, closed-form, data-only, fail-open ([]on ambiguity or a resolve error), ordered by
the existing free-run-length → wall-id → position tie-break, top 3 — never applied. -
Furniture-aware door candidates. For door candidates only, the blocked-span computation now
also subtracts wall runs where a furniture footprint intrudes into the door's approach corridor — the
strip inside the target room along that wall,APPROACH_DEPTH = 900mm deep — so a suggested door
never opens straight onto a piece. Windows are exempt (furniture under a window is normal). The three
door builders (W_NO_ENTRANCE,W_ROOM_UNREACHABLE,W_BATH_VIA_BEDROOM) feed the furniture-blocked
runs intolongestFreeRun; the window builder is unchanged. Fail-open — a furniture-free plan yields
no blocked runs, so every pinned golden (all furniture-free fixtures) stays byte-identical.
Changed
- The generated agent spec now teaches attachment-first through its worked example.
scripts/gen-llm-spec.ts'sSPEC_EXAMPLESswaps the coordinate-mathstudio.archfor the
attachment/strip/anchorattached.archas the flagship worked example (parametric.archstays second
as the sanctioned computed-atidiom); neitherexamples/*.archfile changed. The## Common mistakestable is rewritten from coordinate fixes to attachment-first guidance (off-wall opening →
on <wall> at <pos>, hosted by construction; hand-summed room offsets →strip; a guessed furniture
at→in <room> anchor <9-point>), keeping the genuinely universal rows (mm units, +y down, unique
ids). The fix-topology prose now names all four suggest kinds and leads witharch suggest --json.
spec.llm.mdregenerated (~15.9 → ~14.8 KB;llms-full.txtregenerated in the same chain). SKILL.mdanchor grammar corrected. The staleanchor <corner|edge>placeholder becomes the real
nine-point token list (top-left, top, top-right, left, center, right, bottom-left, bottom, bottom-right),
and the topology section names all four suggest faults and notes the candidates are furniture-aware.- CLI / MCP prose lists all four suggest kinds. The
arch suggestusage line (src/cli.ts), the
cmdSuggestdoc comment (src/cli/commands-author.ts), and the MCPsuggesttool description
(packages/mcp/src/server.ts) now name unreachable / no-entrance / bath-via-bedroom / windowless-bedroom
and note the attachment form + furniture-awareness. No wiring change — the rawSuggestion[]passes
through untouched. The MCP shim republishes as@chanmeng666/archlang-mcp@0.2.1(version-bump-only
release so the refreshed tool description actually reaches npm and the MCP registry — the release
workflow's idempotency guard would have skipped an unbumped 0.2.0). suggestTopology's pre-existingW_ROOM_UNREACHABLEbuilder is now gated on the plan having an
entrance. An entrance-less plan previously produced per-roomW_ROOM_UNREACHABLEsuggestions; it now
yields the singleW_NO_ENTRANCEsuggestion instead, matching the lint's own suppression behavior (the
reachability rule reports no-entrance, not per-room unreachability, when there is no way in). No pinned
golden is affected — the existingfaultyfixture has an entrance.- Note (eval baseline):
spec.llm.mdis the eval's author prompt, and this change replaces a worked
example in it, so it now differs from the prompt behind the calibrated live baseline. No scoring/judge/fixture
code changed; re-running the paid live baseline under the new prompt stays a separate, owner-approved action
(default: not run).
v1.15.0
Roadmap Tranche 6 resolved (2026-07-12): Gate G2 closed with residual area failures = 0/8
on the calibrated baseline (docs/research/2026-07-g2-verdict.md) — the T6 area-syntax sugar
is parked behind frozen reversal triggers, and only the tranche's unconditional Track B
items ship below.
Added
matchVocabulary— one shared closed-vocabulary matcher, and the advisoryW_ALIAS_MATCH.
The token-bounded matcher core (normalizeLabel/synonymMatchesLabel) moved from
src/intent-concepts.tsinto newsrc/vocabulary.ts, and the scattered room-label regexes in
analyze.ts/analyze/circulation.tsare re-expressed as its data-drivenUSE_VOCABULARY
(canonical vs alias words per use kind). One matcher core, two vocabularies at two layers — the
brief-levelCONCEPTStable andSYNONYMS_VERSIONare untouched (judge fixture byte-green; no
second concept table). New advisoryW_ALIAS_MATCHfires when a room with no authored
usesclassifies only via an indirect alias ("Powder" → WC, "Foyer" → entry), carrying a
machine-applicable fix that inserts the explicituses …; corpus classification is pinned
byte-identical bytest/vocabulary-equivalence.test.tsover every example and eval golden.rankFixes— deterministic cost ordering for a diagnostic's fix alternatives (exported).
Orders the mutually-exclusivefixeson one diagnostic by applicability rank → total edit
magnitude (smallest change wins) → earliest offset → stable index.arch fixnow applies only
the top-ranked alternative per diagnostic; LSP code actions present alternatives in the same
canonical order. Identity on today's singleton arrays, so existing behavior is byte-identical.describe().freedom— a degrees-of-freedom placement report (append-only). Per placed
element, whether its position was authored absolutely or derived by the resolver — rooms
absolute/relational/strip, openingsattached/absolute, furniture
anchored/against-wall/absolute— as per-family counts plus oneelementsrow each.
Facts only (ADR 0005); the internal marker never reaches the Scene, so rendered output is
unchanged.- Optional metric unit suffixes on numeric literals (roadmap Tranche 6 Track B). A number may
carry amm/cm/msuffix, folded to millimetres at lex time:3m→3000,3.5m→3500,
3cm→30,3mm→3(an explicit no-op). Bare numbers still mean millimetres, so every
existing plan's output is byte-identical (a determinism/byte-equality test compiles a suffixed
plan and its bare-mm twin and asserts equal SVG). The conversion is exact — decimal-point
shifting on the digit string, never a floating-point multiply — so3.333mis exactly3333and
0.0005mis exactly0.5mm. The suffix must sit immediately after the digits (no space) and
does not fire when a letter follows (3meters= number3+ identmeters); each component of a
WxHliteral may carry its own suffix (3mx4m,3.5mx4200). Deliberately no area unit
(m²) — that belongs to the parked T6 area syntax (Gate G2 closed; see
docs/research/2026-07-g2-verdict.md). The formatter normalises a suffixed literal to its mm
value (3.5m→3500). Folded in the lexer (src/lexer.ts); the grammar source of truth
(src/grammar/tokens.ts) and every generated artifact — editor grammars,grammars/archlang.gbnf,
spec.llm.md,llms-full.txt— carry the optional suffix. - Note (eval baseline):
spec.llm.mdis the eval's author prompt, and this change adds a line
to it, so it now differs from the prompt behind the 2026-07-11/12 calibrated live baseline. No
scoring/judge/fixture code changed; re-running the paid live baseline under the new prompt stays a
separate, owner-approved action (default: not run).
Changed
arch fixnow collects fixes from lint diagnostics too (previously compile-stage
diagnostics only).W_ALIAS_MATCHis the first lint rule to carry a fix; the L1 gate's
l1Pipelineremains the compile-stage-fix +repairreference pipeline and is unaffected.- A room labelled with a WC-only alias (e.g. "Powder") now classifies as a WC. The word was
dead in the old regex cascade (WC_REwas only consulted afterWET_RE, which never matched
it); the vocabulary form resolves it, flagged byW_ALIAS_MATCH. The one deliberate
reclassification — every other label classifies exactly as before (pinned by test).
v1.14.0
v1.14 Tranches 1–2 + 4 — the measurement foundation, then the intent channel it licensed
(roadmap docs/research/2026-07-roadmap-proposal.md). Tranches 1–2 were repo-internal (eval/ and
CI only; the one core exception is the repair() purity fix under Fixed): fix the ruler before
measuring capability. Gate G1's PASS then cleared Tranche 4, which DOES extend the published
surface — the intent channel below.
Added — Tranche 4: the intent channel (2026-07-12; core + CLI, zero new runtime deps)
src/intent.ts— the judge-v2 scoring core, lifted into the core package. A brief's
checkable expectations as data (Intent), lowered to the shallow predicate kinds
(room-count/room-exists/room-area/total-area/adjacent/reachable, plus a
new gatingroom-windows), checked againstdescribe()facts.
validateIntent(source, intent)→{ ok, satisfied, total, violations, subscores, assertions, diagnostics }with typed, catalogued violations and Nickel-style spanless blame
messages (intent /roomsInclude/1: no room matching concept "bathroom" …);
intentFromJson(zero-dep pathed shape walker);feedbackForResult(deterministic
per-violation correction prompts — advisory data, ADR 0005, never auto-applied).src/intent-concepts.ts— the concept vocabulary, now production name resolution. Byte-
mirrors the eval's table; a known concept resolves exactly as the eval judges (label →
room_type→uses, token-bounded), an unknown one falls back to a literal
id → label → uses → room_type match.- Eight catalogued codes:
E_INTENT_ROOM_MISSING/_ROOM_COUNT/_ROOM_AREA/
_TOTAL_AREA/_NO_WINDOWgate;E_INTENT_NOT_ADJACENT/_NO_DOOR/_UNREACHABLEare
advisory (gate: false— scored, never failingok;reachableblames by cause: no entrance
→NO_DOOR, cut-off rooms →UNREACHABLE). Promoting adjacency/reachability to gating stays
parked on T3's still-open loop-vs-resampling question. schemas/intent.schema.json(npm run gen:intent-schema, drift-tested, served by the docs
site). Its field docs make Gate G1's two lessons normative: the area band conventions
("about/~/bare N m²" → ±10%; "at least N" →minonly; qualitative words → no assertion) and
the count discipline ("assert a room count only when the brief enumerates it").- CLI:
arch validate --intent <intent.json>(the gate — exit 2 on a gating violation;
composes with--graph/--strict;--feedbackappends the correction prompts) and
arch score <file> --brief <intent.json>(the continuous meter —satisfied/total+
subscores, exit 0 on any successful measurement). describe()windows gainfacing: "N"|"S"|"E"|"W"(append-only; the outward normal of the
window's host wall), and intentwindowsassertions take an optionalfacing.- The eval now consumes the same implementation (
eval/assertions.ts/synonyms.tsare thin
re-export shims; run.ts'sExpectis the productionIntent) — one judge, zero eval↔prod
skew.JUDGE_VERSIONstays "2", proven by a pinned fixture (eval/judge-fixture.json+
test/eval-fixture.test.ts) that every corpus per-assertion judgment is byte-identical across
the lift; the fixture is regenerated only to record an approved bump, never to green a red suite.
Added — release engineering: tokenless OIDC publishing (npm + MCP registry)
.github/workflows/release.yml— av*tag push (or manual dispatch) publishes the core,
then the MCP shim, to npm via OIDC trusted publishing with provenance (no npm token exists
anywhere; each package carries a one-time Trusted Publisher registration on npmjs.com pointing
at this workflow), then syncs the MCP registry withmcp-publisher login github-oidc—
also tokenless. Every step is idempotent (versions already on a registry are skipped, and the
registry sync is guarded by the registry's own state), so partial failures re-run safely.
Replaces the local granular-token publish flow that npm is deprecating through 2026–2027.- MCP shim 0.2.0 (
@chanmeng666/archlang-mcp, registry entry updated): thevalidatetool
takes an optionalintent(gating assertions fail it; advisory ones score), a newscore
tool is the continuous satisfaction meter, andintent.schema.jsonships as the
intent-schemaresource — the sameintentFromJson/validateIntent/feedbackForResultpath
the CLI uses. - Provenance gotcha, recorded: npm E422-rejects a publish whose
package.json
repository.urlcasing differs from the OIDC-attested repo (ChanMeng666, not
chanmeng666) — fixed in both package.json files + server.json.
Added — Gate G1 verdict + the L2 experiment harness (2026-07-12; still repo-internal)
- Gate G1: PASS (
eval/g1/— generator harness, generated intents, double-blind scores,
report). NL→intent-JSON per-assertion faithfulness on all 26 briefs: 154/157 (98.1%) vs
93.4% per-assertion accuracy of direct.archgeneration (one-tailed z = 2.08, p = .019;
valid-only sensitivity variant below resolution — recorded). The intent channel (roadmap T4:
src/intent.ts,arch validate --intent,intent.schema.json) is cleared for a future
release. The generation prompt is oracle-isolated andtest/g1.test.tsenforces it. - T3 harness: the L2 tier (
eval/l2.ts+eval/l2-run.ts+.github/workflows/eval-l2.yml,
npm run eval:l2). Diagnostic feedback loop (≤2 rounds, fed only compile/lint diagnostics +
fix --dry-runpreviews + trimmeddescribe()— oracle-isolated) against an equal-token-budget
i.i.d. resampling control (Olausson accounting, round-up favours the control), per-metric
best-of, mean±σ across trials,pass@n/pass^n, retrying author + per-brief error isolation.
Offline-tested (14 tests). The live experiment has not been run (cost declined) — the
loop-vs-resampling question remains open and no loop-gain claim is made.
Added — judge v2: brief-grounded intent scoring
- Intent-assertion scoring core (
eval/assertions.ts,JUDGE_VERSION = "2").scoreSourceno
longer greps the goldens for label substrings and golden-derived area bands; it lowers each brief
to a small intent-assertion data structure — the shallow five kindsroom-count/
room-exists/room-area/total-area/adjacent/reachable— and checks the model's
plan against those. The five-kind boundary is deliberately the one a futuresrc/intent.tscan
lift wholesale (Tranche 4 hook).Scoregains append-onlysubscores/assertions/
judgeVersionfields. - Oracle-isolated synonym table (
eval/synonyms.ts,SYNONYMS_VERSION = 1). Room-label matching
runs through a versioned, never-shown-to-the-model concept table with token-bounded,
one-room-one-concept greedy assignment — so "wc"/"toilet"/"bath" resolve to one concept without
leaking the answer into the prompt. - Brief-grounded area checks. Area is verified only where the brief states a number, in a
±10–15% band around the brief's number; all 20 golden-derived bands were deleted. Qualitative
size words ("compact", "generous") carry no cap yet (a documented tier-b hook, added the day a
real "oversized compact" instance appears). - Frozen corpus-review rubric (
eval/rubric.md). Blind-drafted by an isolated agent, then frozen
with the approver's decisions: room-count policy B (a ±1 surplus passes the gate only when the
extra room is pure circulation, operationalized asplanCirc >= expectedCirc + 1); one-room-one-concept
greedy assignment; qualitative size words carry no cap. Adjacency and reachability score as
subscores only, never a gate (Tranche 4 hook). - Corpus 22 → 26. Three prompts amended so every room count is brief-derivable
(two-bath-flat,against-wall-bath,accessible-bath), plus a new per-room-area slice
(sized-kitchen-flat,sized-bedrooms,sized-wet-room,sized-office-mix) so the area dimension
is no longer total-only (H5) — every band carries the brief-source quote it came from. - L1 deterministic-tool gate (
eval/faults/,eval/l1.ts,test/fault-injection.test.ts, in CI
vianpm test). Six single-defect fixtures (off-wall door/window/opening, furniture-through-wall,
blocked-doorway, and a combined case) prove thel1Pipeline— a bounded machine-applicable-fix
fixpoint (mirroringarch fix) followed byrepair(), in the ADR 0011 → ADR 0006 order — heals
every defect class deterministically and idempotently, and is a byte no-op on a clean golden. --l1live overlay (eval/run.ts, live runs only). Reports the deterministic dividend
ΔL0→L1 (whatfix+repairrecover for free, zero extra API calls) with a per-row heal column;
the committed baseline delta stays L0-only so cross-run comparisons don't silently fold the tool
tier into a model score.- eval-live workflow inputs (
.github/workflows/eval-live.yml): a--l1toggle (default on) and
the corpus-coveringmaxdefault of 26.
Changed — live-harness integrity
- Token budget & determinism. Anthropic
max_tokens2048 → 16384 (reasoning models spend
thinking tokens out of the completion cap — the 2048 ceiling truncated output into false
invalidity) withtemperature: 0and ephemeral prompt caching; the OpenAI path pins
seed = 20260711and recordssystem_fingerprint(temperature deliberately not sent). --budget <n>tok|<n>usdcircuit breaker — a pre-call estimate halts the run before it
overspends; skipped briefs are excluded from the denominators (over-estimating direction, verified
price map).- Cross-judge guard.
Baselinenow carries ajudgefield andrenderDeltaflags any delta
taken across a judge-version change as non-comparable — a judge change is never a capabilit...
v1.13.0 — AI-native authoring
The AI-first release: agents write plans without doing coordinate arithmetic, and fix them mechanically.
- Placement sugar —
door|window|opening on <wall> at <pos>attachment,swing into <room>,hinge near start|end,furniture in <room> centered | anchor <corner> [inset N], andstriproom rows. Attached openings cannot be off-wall by construction. - Machine-applicable fixes —
Diagnostic.fixes(rustc-style 4-tier applicability),arch fix(piece-table applier, bounded self-checking fixpoint),arch suggest(candidate doors/windows for unreachable rooms as data, never auto-applied), LSP quick-fixes in the VS Code extension. - Structured I/O — Plan JSON in/out (
compile --from-json,arch ast) aligned to the academic LLM floor-plan schema,validate --graphintent checking,arch complete, generatedschemas/plan.schema.json. - Constrained decoding — generated
grammars/archlang.gbnfso llama.cpp / vLLM-class stacks can hard-guarantee valid.arch. - Zero-dep perception —
arch compile -f txt/preview --asciirenders a box-drawing floor plan any sandboxed agent can read. - Eval — live authorability eval (OpenAI provider, cost-guarded), corpus 18→22, recorded baseline + delta reporting.
- MCP — new optional
@chanmeng666/archlang-mcpstdio shim (ADR 0012); the CLI stays the primary agent interface and the core stays zero-dependency.
See CHANGELOG.md for the full tranche-by-tranche detail.
v1.12.1
Fixed
- The PNG backend's lazy
import("node:fs")/import("node:url")(font lookup) now carry
/* webpackIgnore: true */ /* @vite-ignore */like every other Node-only lazy import, so a
webpack/Next.js consumer importing the core client-side no longer fails its build trying to
resolvefsfor the browser (the code path never runs in a browser; same class of bug as the
1.0.0 → 1.0.1 fix). Found by ArchCanvas's first in-browser use of the core.
v1.12.0
AI-first release (Mermaid-inspired): make ArchLang maximally discoverable, self-describing and
distributable for AI agents. Default SVG output stays byte-identical throughout; every new output
behavior is opt-in (ADR 0007 discipline).
Added — agent context & diagnostics
llms-full.txt(generated, drift-tested vianpm run gen:llms/scripts/gen-llms-full.ts):
the full language spec, theSKILL.mdagent workflow, a manifest-derived CLI reference and the
complete diagnostic catalog bundled into one system-prompt-ready document (~40 KB). Ships in the
npm package; the docs site now serves/llms.txtand/llms-full.txtat its root
(copied intodocs-site/public/bysync-docs.mjs, per llmstxt.org convention).arch context: prints the bundle — one command gives a cold-start agent everything
(arch specremains the language-only view).diagnosticToJson(source, d)+DiagnosticJson(newsrc/diagnostic-json.ts, exported):
the CLI's agent-facing diagnostic projection (line/col from byte spans + cataloguedfix) is now
public API for SDK/playground/LSP consumers. CLI JSON output is byte-identical.
Added — always-visible errors & eval spine
- Opt-in error-card SVG:
compile(src, { onError: "svg" })/--error-svgon
compile/preview/md— a plan that fails to compile still renders a deterministic,
self-describing SVG card (severity, code chip, line:col, message, catalogued fix; new
src/backends/error-svg.ts, exportedrenderErrorSvg). Errors/diagnostics/exit codes are
unchanged; without the opt-in, a broken plan still produces no bytes.arch md --error-svg
renders failing fenced blocks as error cards instead of skipping them. Also exported:
renderPngFromSvg(raster core extracted from the PNG backend). - Authorability eval hardened: corpus grown 3 → 18 briefs with hand-verified goldens
(relational placement,dims auto,against wall, multi-bath topology, open-planopening,
accessibility briefs, scripting, an intentional-warning shell, 30–126 m²); offline golden
regression gate wired into CI (npm run eval:ci, no API key); default live-eval model id
updated.
Added — distribution
- Docs site: plain
```archfences in any docs page now render as live, editable
<ArchLive>widgets (markdown-it fence transform; SSR/no-JS keeps the highlighted block;
```arch staticopts out). Explicit<ArchLive>usage is untouched. - GitHub Action
.github/actions/arch-render(composite, in-repo): render every fenced
```archblock in a repo's Markdown viaarch md— inputsfiles/format/out-dir/
error-svg/version, with a self-test workflow. Witherror-svg: true(default) broken blocks
become error-card images and the job stays green. - Playground: Copy-for-LLM button (current source +
describe()facts + diagnostics with
fixes + spec pointer as one paste-ready prompt; purebuildLlmPrompthelper) and diagnostics
now show their catalogued fix inline (full cause/example still behind the disclosure).
Added — accessibility as a language feature
compile(src, { accessible: true })/arch compile --accessible: the SVG carries
<title>(plan name),<desc>(a derived one-sentence caption) androle="img"+
aria-labelledby. The caption is also exposed asdescribe().caption(same sentence,
guaranteed identical). Default output byte-identical without the flag.accTitle/accDescrplan-level keywords (the release's one language-surface change):
explicit accessible metadata overriding the derived title/caption. Duplicate → new
W_DUP_ACC_METADATA(last wins); misplaced → newE_ACC_PLACEMENT. Grammar/spec/editor
artifacts regenerated; newexamples/accessible.arch;arch fmtprints and preserves both.
VS Code extension repack required (it bundles the core).
v1.11.0
Added
- Annotate mode now stamps
data-arch-id/data-arch-kindon element primitives.
data-arch-kindis stamped for every element kind exceptwall— currentlyroom,
door,window,opening,furniture,dim, andcolumn(the non-wall members of
ElementKind; the set is open-ended and grows as kinds are added). Walls are excluded —
their SVG is unioned geometry stitched across many statements, so per-element attribution
is ambiguous. Default (non-annotate) output remains byte-identical. diffPlans(sourceA, sourceB, opts?): deterministic semantic diff of two plans built on
describe()— room/opening/furniture changes, per-room bbox edge deltas, circulation deltas,
and human-readable summary sentences.
v1.10.0 — human circulation + foundation refactor
Human circulation (ADR 0008)
Circulation analysis grows from "is every room reachable?" to "how far, how wide, how direct is the walk?" — strictly facts + advisory + explicit transform (no generative layout; default SVG output byte-identical, pinned by tests):
- Facts —
describe().circulation: per-room walk distance, bottleneck clear width, and detour ratio from the entrance, plus key routes (kitchen↔living/dining, bedroom↔bath), on a clearance-eroded navigation grid. - Lint —
W_PATH_TOO_NARROW(default 700 mm;accessibility-advisoryprofile: 900 mm) andW_CIRCUITOUS_PATH(>3.0× straight-line). - Overlay —
arch compile --overlay circulation/compile(src, { overlays: ["circulation"] })draws the walks, key routes, and bottleneck markers; the playground gains an off-by-default Paths toggle. - Repair guard —
arch repairdeclines any furniture move that would newly pinch a walk below the lint threshold and reports it inunresolved.
Foundation refactor (default output byte-identical)
- Wall-union rewritten: opening-heavy
toScene~19.5 → ~2.6 ms (full compile ~42 → ~24 ms);validate/lintno longer render the SVG they discard. lint()restructured to one module per rule over a shared context; shared rect geometry (geometry/rect.ts) and one deterministic number formatter (num-format.ts).- Drift tests pin the element-keyword↔registry, fixture-classifier, completion-kind, and export-format joints; new core exports
COMPLETION_KINDS,EXPORT_FORMATS, optionalScene.chrome. - Tooling: Biome (CI-gated),
noUncheckedIndexedAccesson, Node 18/20/22 CI matrix, honest per-stage benchmarks; the playground app is now TypeScript with its own tests.
Sites
Embeddable playground viewer (embed.html + Embed button), IDE-parity actions (Format / Repair panel / clickable diagnostics), live editable <ArchLive> docs examples.
Suite: 535 tests · typecheck/Biome/gen-drift clean · all default artifacts byte-identical to v1.9.0.