Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
ceb49d7
amico-run(#108): B1 — generalize amico-run into the `amico` verb router
aarontrowbridge Jul 9, 2026
5c490e5
feat(entities): composite System schema + enums + validation
aarontrowbridge Jul 9, 2026
0e90f36
feat(entities): normalizeSystem (flat->N=1) + composite merge/toml/hash
aarontrowbridge Jul 9, 2026
07a6c08
feat(entities): topology expansion + homogeneous replicate
aarontrowbridge Jul 9, 2026
e13e9d6
feat(tools): composite-aware pick_system/set_model (F1 + F2)
aarontrowbridge Jul 9, 2026
99e8335
feat(amicode-prompt): structure-first + frontier-batched multipartite…
aarontrowbridge Jul 9, 2026
c60420f
feat(amicode): composite->solve.jl authoring map + golden skeleton fi…
aarontrowbridge Jul 9, 2026
d56beb0
fix(amicode-prompt): keep agents_md test invariants after interview r…
aarontrowbridge Jul 9, 2026
0fd846d
amico catalog(#111): B2 — real repertoire query + verified ingest verb
aarontrowbridge Jul 9, 2026
acbf3ea
merge origin/main into local/composite-system
aarontrowbridge Jul 9, 2026
70eea56
amico vault/device/note(#113): B3 — migrate the remaining bookkeeping…
aarontrowbridge Jul 9, 2026
1375829
Stage library skills by surface:product tag, not a hardcoded list
aarontrowbridge Jul 9, 2026
7d2ffb2
feat(amicode): Formulation typed-facet schema + enums (spec §3 / plan…
aarontrowbridge Jul 9, 2026
b2f9fcd
feat(amicode): normalizeFormulation + updateFormulation + shared migr…
aarontrowbridge Jul 9, 2026
0c78beb
feat(amicode): validateFormulation (structured) + formulationWarnings…
aarontrowbridge Jul 9, 2026
918f4bd
feat(amicode): structured formulationToml round-trip + migrate legacy…
aarontrowbridge Jul 9, 2026
fa044bd
feat(amicode): amicode_formulate typed facets + normalize both read s…
aarontrowbridge Jul 9, 2026
fe5a714
docs(amicode): formulate stage rewrite + Formulation→Piccolo authorin…
aarontrowbridge Jul 9, 2026
486df63
feat(device-mgmt): QICK job-server queue contract + MockJobServer (Sp…
aarontrowbridge Jul 7, 2026
6270bf8
feat(device-mgmt): calibration graph loader (acyclic) + total evaluat…
aarontrowbridge Jul 7, 2026
dc70f81
feat(device-mgmt): pure device calibration registry — state.json/hist…
aarontrowbridge Jul 7, 2026
0279c83
feat(device-mgmt): device-status projection + queue-aware nextActions…
aarontrowbridge Jul 7, 2026
3c5f45b
feat(device-mgmt): QICK HTTP client (Schuster/MCP) + package-entitlem…
aarontrowbridge Jul 7, 2026
aac54f4
feat(device-mgmt): device inspector webview (sibling to run inspector…
aarontrowbridge Jul 7, 2026
48942e0
feat(device-mgmt): register device inspector view + commands + poll l…
aarontrowbridge Jul 7, 2026
4b68f87
test(device-mgmt): Spec A §6 acceptance sweep (MockJobServer + Snowbi…
aarontrowbridge Jul 7, 2026
15f01b6
feat(device-mgmt): locked premium node = Intonatissimo funnel, not a …
aarontrowbridge Jul 7, 2026
abb1d72
fix(device-mgmt): port device inspector to redesigned inspector idiom…
aarontrowbridge Jul 10, 2026
844c763
feat(chat): Claude Code-style output formatting — AGENTS.md style rul…
aarontrowbridge Jul 10, 2026
e5b6357
chore(vendor): lock ref -> d073fb617d (default.txt/gemini.txt rich-ou…
aarontrowbridge Jul 10, 2026
cef8fd9
chore(vendor): lock ref -> 153278891c (model-agnostic communicating.txt)
aarontrowbridge Jul 10, 2026
a8ed5fa
chore(vendor): lock ref -> c42043e555 (rydberg Hamiltonian fix + agen…
aarontrowbridge Jul 11, 2026
2a066e2
chore(vendor): lock ref -> f78155a060 (markdown heading hierarchy)
aarontrowbridge Jul 11, 2026
532b267
feat(device-mgmt): gate Device Inspector to open-on-button-press (ali…
aarontrowbridge Jul 11, 2026
94e555d
feat(mounts): Armonia mount-stack resolver — markers + mounts.toml pr…
aarontrowbridge Jul 11, 2026
83d608a
feat(substrate): mount_store — full Armonia mount-stack discovery + p…
aarontrowbridge Jul 11, 2026
5bf6fb7
feat(vault): mount-aware status/resolve + union query over the Armoni…
aarontrowbridge Jul 11, 2026
c0e0154
feat(substrate): mount-stack + memory-index splice sections (spec-202…
aarontrowbridge Jul 11, 2026
c4ec87b
feat(note): note route — routed generic note writes by intent + route…
aarontrowbridge Jul 11, 2026
b7270e7
feat(config): per-mount grants + mount-stack/memory splice at session…
aarontrowbridge Jul 11, 2026
05cc830
feat(distiller): typed memory store writes + MEMORY.md index (spec-20…
aarontrowbridge Jul 11, 2026
5bd0bd5
Merge branch 'surface-based-skill-staging' into local/night-preview-2…
aarontrowbridge Jul 11, 2026
f91ab25
Merge branch 'aaron/mount-stack-parity' into local/night-preview-2026…
aarontrowbridge Jul 11, 2026
7189329
Merge branch 'aaron/vault-mounts-verbs' into local/night-preview-2026…
aarontrowbridge Jul 11, 2026
c5bb261
Merge branch 'local/device-management' into local/night-preview-20260711
aarontrowbridge Jul 11, 2026
a7d9bdb
fix(build): svg text loader on the device-inspector webview bundle
aarontrowbridge Jul 11, 2026
4c45533
feat(ship): package the amico verb launcher + teach the bookkeeping v…
aarontrowbridge Jul 11, 2026
4037a9e
Merge branch 'aaron/ship-amico-verbs' into local/night-preview-20260711
aarontrowbridge Jul 11, 2026
1bc0dd5
feat(pitch): capability answer composes live from the user's spliced …
aarontrowbridge Jul 11, 2026
251ad36
fix(pitch): keep the author-first posture line as a required element
aarontrowbridge Jul 11, 2026
5b11890
Merge branch 'aaron/ship-amico-verbs' into local/night-preview-20260711
aarontrowbridge Jul 11, 2026
25785ef
merge: consolidate night-preview into composite-system (full extensio…
aarontrowbridge Jul 11, 2026
06e67fe
feat(amicode): amicode.defaultModel setting — a discoverable default-…
aarontrowbridge Jul 12, 2026
01e0a38
feat(amicode): chat_panel set-default-model bridge → amicode.defaultM…
aarontrowbridge Jul 12, 2026
f482031
fix(amicode): stop force-pinning a fallback model that overrode user …
aarontrowbridge Jul 12, 2026
4b4af0e
docs(amicode): user-facing docs + open-core README rewrite
aarontrowbridge Jul 14, 2026
d55b1aa
feat(chat): bidirectional clipboard bridge — copy-back + image paste
aarontrowbridge Jul 14, 2026
8b41668
merge main (solver wire #127) into composite-system — resolve opencod…
Rchari1 Jul 14, 2026
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
99 changes: 77 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,95 @@
<div align="center">

<picture>
<source media="(prefers-color-scheme: dark)" srcset="packages/extension/media/amico-tab-dark.svg">
<img alt="Amicode" src="packages/extension/media/amico-tab-light.svg" width="96">
</picture>

# Amicode

A VS Code extension for agentic quantum-control pulse optimization — natural-language chat → LLM-authored Julia solve (Piccolo/Piccolissimo) → live run inspector → per-lab pulse catalog. Deployed onto partner-lab machines; a vendored [opencode](https://github.com/sst/opencode) binary provides the chat/LLM harness.
### Quantum optimal control, driven by conversation.

Describe the gate you want in plain language. Amicode designs the pulse, runs the
solve, and shows you the result — without leaving your editor.

<sub>A VS Code extension · built on [Piccolo.jl](https://github.com/harmoniqs/Piccolo.jl) · chat harness vendored from [opencode](https://github.com/sst/opencode)</sub>

</div>

---

Amicode turns a natural-language description of a control problem into an
LLM-authored Julia optimization, runs it, and streams the result back into native
editor panels. The physics, the solver idioms, and your lab's accumulated
knowledge all ride along as context — so the script it writes is correct by
construction, not by luck.

## What it does

> ## ⚠️ Source of truth = the design docs, not this code
>
> This repository's **authoritative design lives in the `harmoniqs/amico` vault**, in this order of authority (architecture → context → diagrams → interfaces → planning → plans → specs). When code and docs disagree, **the docs win.** Scope, architecture, and interface changes happen in the vault docs first, then flow to code and issues.
**Conversational solves.** Ask for a gate or a state preparation; Amicode writes a
self-contained Piccolo script, runs the Ipopt solve, and captures the result. No
boilerplate, no parameter-guessing.

| # | Authority | Location in `harmoniqs/amico` |
|---|-----------|------------------------------|
| 1 | **Architecture + diagrams + interfaces** (container, solve lifecycle, chat→solve→inspector sequence, run-dir contract, provisioning flow, module decomposition §5, dependency graph §7) | [`vault/specs/spec-20260529-amicode-architecture.md`](https://github.com/harmoniqs/amico/blob/main/vault/specs/spec-20260529-amicode-architecture.md) |
| 2 | **Context / requirements** (problem, solution, user stories S1–S38 with acceptance criteria, stable interface contracts, risks) | [`vault/specs/spec-20260529-amicode-prd.md`](https://github.com/harmoniqs/amico/blob/main/vault/specs/spec-20260529-amicode-prd.md) |
| 3 | **Decisions** (decision log D1–D10; 157 resolved/deferred open questions) | [`vault/specs/spec-20260529-amicode-open-questions.md`](https://github.com/harmoniqs/amico/blob/main/vault/specs/spec-20260529-amicode-open-questions.md) |
| 4 | **Project-management plan** (phases β→4, tasks β.1–4.2, per-phase Definition of Done, dependency-ordered parallel-engineer schedule, ~56-pd estimate) | [`vault/plans/plan-20260603-124231-amicode-phased-build.md`](https://github.com/harmoniqs/amico/blob/main/vault/plans/plan-20260603-124231-amicode-phased-build.md) |
| 5 | **Review / QA** (60-agent swarm review; consolidated findings) | [`vault/reviews/review-20260603-amicode-plan-swarm.md`](https://github.com/harmoniqs/amico/blob/main/vault/reviews/review-20260603-amicode-plan-swarm.md) |
**Physics that ships with the tool.** Platform references for neutral-atom Rydberg,
transmon, fluxonium, trapped-ion, and bosonic systems load on demand — the
Hamiltonians, drive conventions, and construction patterns are inlined into each
script so it stands on its own.

Access requires the `harmoniqs/amico` vault repo. (We chose reference-only over copying the docs in, to keep a single source of truth and avoid drift.)
**Your knowledge, mounted.** Amicode reads your **Armonia** — the stack of vaults
you mount (personal, team, public). Notes, specs, experiment history, and your
pulse catalog become first-class context the assistant plans against.

## Status of the code in this repo
**A live run inspector.** Watch a solve converge in real time: overlaid pulse
plots, fidelity and constraint-violation traces, per-run metrics. Every run is
captured and revisitable.

`src/` is the **v2 spike** — a working chat→solve→inspector prototype (CLI-direct, after the pivot away from MCP + callback-HTTP). It is a **starting point, not the authority.** Per the design audit (vault decision log D9/D10), the following are explicitly in flux or superseded — do not treat them as canonical:
**A pulse catalog.** A versioned, warm-startable library of your best pulses —
retrieve the incumbent for a `(platform, gate)`, warm-start from it, and promote a
new best when you beat it.

- **`bin/amico-run`** — being re-architected into the **D9 thin orchestrator** (spawns `julia <script>`, writes `manifest.toml` + `FINISHED` from outside Julia; passes a lab *pointer*, never parsed params). The current flag-parsing form is pre-D9.
- **`spike_solve.jl`** (in the legacy `amico/amicode/julia/` tree, not extracted here) — a **frozen demo spike**, superseded. Production solves are **LLM-authored Julia scripts** using Piccolo's existing public API (`TransmonSystem(; ω, δ, levels)`, `load_pulse`, JLD2 `save`, the Ipopt callback) per **D10** — not a parameterized `spike_solve.jl`.
- **MCP / callback-HTTP references** in `test/` — vestigial from the pre-pivot design; slated for removal.
**Straight to hardware.** Drive real RFSoC devices through the QICK backend, or run
the *entire* closed loop against a pure-Julia mock with zero hardware for
development and CI.

## Build & distribution
## Hardware — QICK / RFSoC

- **Phased build:** see the plan (authority #4). **Phase β (Schuster demo)** is first — gated by packaging/glue (vendor opencode, bundle the solve script, provision the Julia project), not by Julia solver work (which already ships in Piccolo `main`).
- **Issues** are generated from the PRD + plan (authorities #2/#4) via the `amico:prd-to-issues` skill — *driven by the plan's phase/task decomposition, not by reading this spike code* — onto GitHub Projects board #4 (org `harmoniqs`), labeled `phase:β`…`phase:4` + `area:*`.
Amicode's hardware path is [**IntonatoQICK.jl**](https://github.com/harmoniqs/IntonatoQICK.jl),
a QICK backend that bridges an optimized pulse to an RFSoC board over a deliberately
**coarse three-verb boundary** (`upload_pulse!` / `trigger!` / `readout`). All tProc-v2
specifics live board-side, so the firewall between you and the lab is just a transport.
The whole loop runs — and is tested — with **no Python and no board** via the built-in
mock, then swaps to real hardware unchanged.

## Dev quickstart (spike)
> **QICK v2 backend & docs → [github.com/harmoniqs/IntonatoQICK.jl](https://github.com/harmoniqs/IntonatoQICK.jl)**

## Try it

Open the Amicode panel and paste:

> Design a minimum-time single-qubit X gate for a transmon (3 levels, penalize
> leakage to |2⟩). Then run the optimized pulse through the IntonatoQICK mock
> backend, read out the populations, and plot both the pulse and the readout.

## Open core

The extension and its platform skills are open. **Entitled builds** add
Harmoniqs's proprietary capabilities — GPU-accelerated solvers and **closed-loop
hardware calibration** — unlocked by the packages you have access to. Same
editor, same workflow; what you can reach is set by your entitlements.

## Develop

```bash
pnpm install
pnpm run build # esbuild → dist/extension.js
pnpm test # vscode-shim smoke tests
```

See [`AGENTS.md`](./AGENTS.md) for the in-editor opencode project conventions the extension sets up.
See [`AGENTS.md`](./AGENTS.md) for the in-editor project conventions the extension
sets up.

---

<div align="center">
<sub>Built by <a href="https://harmoniqs.co">Harmoniqs</a> · quantum control, composed.</sub>
</div>
22 changes: 22 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Amicode documentation

Quantum optimal control, driven by conversation. Describe the gate you want in
plain language; Amicode designs the pulse, runs the solve, and shows you the
result — without leaving your editor.

This is the user-facing guide. If you're setting up the repo for development
instead, see [`AGENTS.md`](../AGENTS.md).

## Contents

| Page | What's in it |
|---|---|
| [Getting started](./getting-started.md) | Install the extension, open the chat, and run your first solve. |
| [Features](./features.md) | A guided tour of every surface — conversational solves, platform skills, Armonia, the Run Inspector, the Pulse Catalog, and hardware. |
| [Hardware](./hardware.md) | The QICK / RFSoC path in depth: the three-verb boundary, the pure-Julia mock loop, and swapping to a real board. |

## New here?

Start with [Getting started](./getting-started.md) and run the worked
example — a minimum-time transmon X gate, taken all the way through the QICK
mock backend. Everything else builds on that loop.
68 changes: 68 additions & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Features

A guided tour of Amicode's surfaces. Each one is a place you work, not a thing
you configure — the extension is a workflow, and these are its stages.

## Conversational solves

Ask for a gate or a state preparation in plain language. Amicode writes a
self-contained Piccolo script, runs the Ipopt solve, and captures the result —
no boilerplate, no parameter-guessing. A short guided exchange settles anything
it needs before it commits to code, so the script it produces is correct by
construction rather than by luck. You can stop a solve in flight with **Amicode:
Stop current solve**.

## Platform skills

The physics ships with the tool. Platform references for **neutral-atom
Rydberg**, **transmon**, **fluxonium**, **trapped-ion**, and **bosonic** systems
load on demand — the Hamiltonians, drive conventions, and construction patterns
are inlined into each script so it stands on its own. You never hand the
assistant a Hamiltonian; naming the platform is enough.

## Armonia

Amicode reads your **Armonia** — the stack of vaults you mount. Notes, specs,
experiment history, and your pulse catalog become first-class context the
assistant plans against, so a solve is informed by what your lab already knows.

Vaults layer by scope. A **personal** vault carries your profile, problem cards,
and running memory; **team** and **public** vaults stack on top. Mounts live
under `~/.amico/vaults` and appear in the **Armonia** view in the Activity Bar.
The **Vault** view browses the active vault's notes directly.

## Run Inspector

Watch a solve converge in real time. The Run Inspector overlays pulse plots,
traces fidelity and constraint-violation as they fall, and shows per-run
metrics. It's a webview panel — open it from the status bar or with **Amicode:
Open Run Inspector**, and select any past run with **Amicode: Select run to
inspect…**. Every run is captured to disk and revisitable; you can open a run's
directory on disk with **Amicode: Open current run directory**.

## Pulse Catalog

A versioned, warm-startable library of your best pulses. Retrieve the incumbent
for a `(platform, gate)`, warm-start a new solve from it, and promote a new best
when you beat it. Save the pulse from the current run with **Amicode: Save pulse
from current run**; browse and manage entries in the **Catalog** view. The
catalog is warm-start memory — the next solve for a problem you've already
touched starts from your last good answer, not from scratch.

## Hardware — QICK

Take an optimized pulse straight to a real RFSoC board through the QICK backend,
or run the *entire* closed loop against a pure-Julia mock with zero hardware —
ideal for development and CI. The boundary to the board is a deliberately coarse
three-verb transport, so the same script runs against the mock and the metal
unchanged.

The backend is **[IntonatoQICK.jl](https://github.com/harmoniqs/IntonatoQICK.jl)**.
See [Hardware](./hardware.md) for the full path from mock loop to real board.

## Open core

The extension and its platform skills are open. **Entitled builds** add
Harmoniqs's proprietary capabilities — GPU-accelerated solvers and closed-loop
hardware calibration — unlocked by the packages you have access to. Same editor,
same workflow; what you can reach is set by your entitlements.
76 changes: 76 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Getting started

Amicode turns a plain-language description of a control problem into an
LLM-authored Julia optimization, runs it, and streams the result back into
native editor panels. This page takes you from a fresh install to your first
converged pulse.

## What you'll need

- **VS Code** 1.95 or newer.
- **Julia** 1.12 or newer. The solver runs locally on your machine — Amicode
authors a self-contained Piccolo script and hands it to Julia.
- **A model provider** for the chat. Sign in to your provider once, or set an
API key in your environment; without one, the extension falls back to a free
anonymous tier that works but is best avoided for real work.

## Install and open

1. Install the Amicode extension in VS Code.
2. Open the **Amicode** icon in the Activity Bar. You'll see three views —
**Vault**, **Catalog**, and **Armonia** — and the chat opens on its own once
the assistant is ready. (You can reopen it any time with **Amicode: Open
Chat** from the Command Palette.)

That's it. The first time you run a solve, Julia precompiles its project, which
takes a few minutes; every solve after that is fast.

## The chat panel

The chat is where you do the work. You describe a gate, a state preparation, or
a whole closed loop in ordinary language, and the assistant plans it against the
physics and against your own notes before it writes a line of code. A short
guided exchange fills in anything it needs — levels, drive conventions, what to
penalize — and then it writes the script.

Pick the model from the in-chat model picker at any time; the choice sticks for
that session.

## Your first solve

Open the chat and paste:

> Design a minimum-time single-qubit X gate for a transmon (3 levels, penalize
> leakage to |2⟩). Then run the optimized pulse through the IntonatoQICK mock
> backend, read out the populations, and plot both the pulse and the readout.

This one prompt exercises the whole loop: it names a platform (transmon), a
target (an X gate), a constraint (keep population out of |2⟩), and a hardware
step (the QICK mock backend — see [Hardware](./hardware.md)). You don't need to
know the Piccolo API, the transmon Hamiltonian, or the QICK verbs; the
assistant supplies all three.

## What to expect

The loop runs in three visible beats:

1. **A script is authored.** The assistant writes a self-contained Piccolo
script — Hamiltonian, drives, objective, constraints, and the QICK mock call,
all inlined — and shows it to you in the chat.
2. **The solve runs.** Julia executes the script and the Ipopt solve begins. A
status-bar item tracks it live.
3. **The result is captured.** Open the **Run Inspector** to watch the solve
converge — overlaid pulse plots, fidelity and constraint-violation traces,
and per-run metrics. Open it from the status bar or with **Amicode: Open Run
Inspector**, or turn on `amicode.inspector.autoOpen` to have it reveal itself
when a solve starts.

Every run is captured to disk and stays revisitable — nothing you solve is
thrown away. When you're happy with a pulse, save it to your
[Pulse Catalog](./features.md#pulse-catalog) and warm-start from it next time.

## Where to go next

- [Features](./features.md) — a tour of every surface in the extension.
- [Hardware](./hardware.md) — the QICK / RFSoC path, from the mock loop to a
real board.
61 changes: 61 additions & 0 deletions docs/hardware.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Hardware — QICK / RFSoC

Amicode's hardware path is
**[IntonatoQICK.jl](https://github.com/harmoniqs/IntonatoQICK.jl)**, a QICK
backend that bridges an optimized pulse to an RFSoC board. The design goal is a
single, thin firewall between you and the lab: a pulse you solved in the editor
should reach the board without any transcription, and the whole loop should run
on a laptop with no board attached. This page walks that path.

## The three-verb boundary

The interface to a board is deliberately **coarse** — three verbs, and nothing
else crosses the line:

- `upload_pulse!` — send an optimized pulse to the board.
- `trigger!` — fire the sequence.
- `readout` — pull the measured populations back.

That's the entire contract. Everything tProc-v2-specific — waveform memory,
timing, DAC/ADC plumbing — lives board-side, behind those three calls. The
consequence for you is that the boundary is *just a transport*: nothing about a
particular board leaks into the pulse you designed, and nothing about your pulse
design leaks into the board firmware.

## The pure-Julia mock loop

Every one of those three verbs has a pure-Julia mock implementation. The mock
accepts an uploaded pulse, "fires" it, and returns simulated readout — so you
can run the *entire* closed loop with **no Python and no board**. This is the
default path for development and CI: the worked example in
[Getting started](./getting-started.md) runs against the mock, and the backend's
own test suite exercises the full loop this way.

Working against the mock first is the intended workflow, not a fallback. You
converge the pulse, watch the readout, and shake out the whole sequence long
before a board is in the room.

## Swapping to a real board

Because the mock and the real backend implement the same three verbs, moving to
hardware **swaps the transport and nothing else** — the pulse, the script, and
the readout handling are unchanged. You point Amicode at your board's hardware
profile and the same loop now runs on metal.

The board profile lives in a `lab.toml` (by default `~/.amico/lab.toml`), which
Amicode validates on load. A connected board's live status — its queue and
health — surfaces in the Device Inspector panel; the endpoint you configure is a
pointer only, never credentials.

For the backend itself, its supported firmware, and setup on a specific RFSoC,
follow the backend repository:

> **QICK v2 backend & docs → [github.com/harmoniqs/IntonatoQICK.jl](https://github.com/harmoniqs/IntonatoQICK.jl)**

## Beyond open-loop

Driving a board open-loop — upload, trigger, read out — is open. **Closed-loop
hardware calibration**, which tunes pulses against a live device, is one of the
proprietary capabilities in entitled builds, unlocked by the packages you have
access to. Same editor, same workflow; what you can reach is set by your
entitlements. See [Open core](./features.md#open-core).
22 changes: 15 additions & 7 deletions packages/amico-run/esbuild.config.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { build } from "esbuild";
import { chmodSync } from "node:fs";

await build({
entryPoints: ["src/cli.ts"],
// Two bins from one package: the historical `amico-run` (entry cli.ts) and the new `amico`
// verb router (entry amico.ts, issue #108). Both share the launch path (src/launch.ts);
// amico.ts additionally bundles the spine verbs + the mcp-serve facade.
const common = {
bundle: true,
platform: "node",
target: "node20",
// ESM, not CJS: the package is "type": "module", so node executes dist/amico-run.js
// as ESM — a CJS bundle would die on `require is not defined in ES module scope`.
// ESM, not CJS: the package is "type": "module", so node executes the bundle as ESM —
// a CJS bundle would die on `require is not defined in ES module scope`.
format: "esm",
outfile: "dist/amico-run.js",
banner: { js: "#!/usr/bin/env node" },
sourcemap: true,
logLevel: "info",
});
chmodSync("dist/amico-run.js", 0o755);
};

for (const [entry, outfile] of [
["src/cli.ts", "dist/amico-run.js"],
["src/amico.ts", "dist/amico.js"],
]) {
await build({ ...common, entryPoints: [entry], outfile });
chmodSync(outfile, 0o755);
}
Loading
Loading