swage guide14 screens · 6 transcripts / focus · Esc clear · ← → in the viewer open swage →

Program-as-Weights in one browser tab: a spec is pressed, cold, into a LoRA adapter for Qwen3-0.6B — forward passes only — and the program scores typed decisions on-device. This guide walks each surface with real captures from the running app, and the agent door with real transcripts.

First visit

What a person sees on a cold load, with nothing downloaded and nothing stored: the simple front, and the switch to the workbench.

The page, cold
The page, coldWhat loads in under a second, before any model byte: one sentence on what this is, three honest numbers (340 MB once for the small model, 50 KB per program, under a second per decision), a small/full model switch, a program picker with the three demo programs, an input already filled with a real example, one button, and the demo’s decisions computed when this build was pressed — the time-to-first-value the ≤ 5 s rule asks for.
Picking a program
Picking a programThe picker holds the demo programs (an irreversibility judge, an allow/stage/block policy judge, a customer-intent classifier), then your own, then “+ new”. Picking one shows its spec in a line and its precomputed examples; clicking an example puts it in the input. Nothing downloads until the button.
The advanced switch
The advanced switchOne switch turns the simple front into the workbench: the status strip (GPU, four model states, memory against budget, programs), the program select and interpreter control, score/generate modes, the program panel with id, hash, examples and calibration, and the Programs tab. The preference persists per browser.

Decide

Pick a program, press the one button; it downloads what is missing once, then scores the allowed options — or generates, in advanced mode.

One button does what is needed
One button does what is neededDecide with a demo picked and nothing loaded: the button’s status line said what the click would cost; the click imports the program (50 KB of coefficients, expanded on the GPU from 185 MB of shared bases fetched once), activates it, loads the interpreter (small: 340 MB), then decides — one action, no setup screen.
Loading the interpreter
Loading the interpreterQwen3-0.6B (small tier q4f16, 340 MB; full tier fp16, 1.2 GB) downloads once, hash-verified, into Cache Storage; the status line under the button shows state and progress. Large files come down as parallel byte ranges that resume on error.
A scored decision
A scored decisionScore mode: every allowed option is scored by teacher-forced log-probability of its tokens plus end-of-turn under the program (Touchstone’s rule); the verdict, its probability, and the per-option table follow. Here the program judges pushing a release tag irreversible.
Generate mode (advanced)
Generate mode (advanced)For programs whose output is open-ended: greedy decoding, first line. The same interpreter, the same adapter, no option list. Modes live behind the advanced switch; the simple front scores the program’s own options.
Mark a decision
Mark a decisionThe person’s label goes into the program’s own examples — a regression set the replay harness can run and the temperature fit can use. Mark is person-only: a real click, never the agent door.

Make a program

Press a spec into weights in the tab: the 0.6B writes the pseudo-program, the trained PAW encoder reads it in one prefill, the mapper emits the adapter.

Make a program, empty
Make a program, emptySpec → pseudo-program → encoder → mapper → program, behind one button. The simple form asks for the spec in plain language and the allowed options; the line under the button says what the first press downloads (writer 0.5 GB, encoder 4.6 GB, mapper 0.3 GB, once).
The pseudo-program, written (advanced)
The pseudo-program, written (advanced)With the advanced switch on, Write lets Qwen3-0.6B (thinking off, greedy) draft the PAW pseudo-program in the exact format the trained encoder was trained on; the token meter shows the budget (1 792). Edit it, paste your own, or leave it to Press.
Pressed
PressedOne encoder prefill over chat(spec) + pseudo-program + 64 prefix tokens, 28 tapped layers, the mapper mixes 64 shared bases into a rank-64 adapter. Phase timings shown; the draft is staged until you save it. About 5 s with the encoder resident.
The pressed program, deciding
The pressed program, decidingSaved, picked, and deciding a new input on the simple front. No training happened; forward passes only.

Programs (advanced)

The store: import, export, delete (staged), and the journal.

Programs (advanced)
Programs (advanced)Every program in the store with source (demo · imported · pressed), adapter size and example count; open, export (the PEFT folder paw-server and Touchstone read), or delete. Import by URL, folder picker, or drop. The journal tail shows the last twenty tool calls.
Staged delete
Staged deleteDestructive actions stage: the row dims, a 10-second undo is offered, then it lands. The same rule applies to an agent calling the tool.

Agent door

The same commands as tools on window.swage (and navigator.modelContext where the browser has it). Transcripts from the door itself.

window.swage
> await swage.status()
{
  "ok": true,
  "class": "ok",
  "data": {
    "version": "0.1.0",
    "webgpu": {
      "ok": true,
      "adapter": "apple metal-3",
      "f16": true,
      "maxBufferMB": 4096
    },
    "engine": "up",
    "models": {
      "interpreter": {
        "state": "ready",
        "mb": 338,
        "dtype": "q4f16",
        "size": "small",
        "preference": "small",
        "sizes": {
          "small": 338,
          "full": 1195
        },
        "sha256": {
          "graph": "f9f6a3ade19a803b36567aec3be8ff3a8188df81c83f1c8099569e498b07138d",
          "data": [
            "5dae0670eb709037792a88d098cde450d98d5ff14a9de763d147b12ab6c8b173"
          ]
        }
      },
      "encoder": {
        "state": "unloaded",
        "mb": 4559,
        "dtype": "ort-q8-g64"
      },
      "mapper": {
        "state": "ready",
        "mb": 142,
        "dtype": "fp16",
        "sha256": {
          "graph": "b90df44d33e396360ca340389e6cacce46ca421ea2f51141aca247d11a7c0de1",
          "data": [
            "a1764f612b422296e9b3f7f4596fe992398fd8939e75723f50a081a0e9cde4f7"
          ]
        }
      },
      "expand": {
        "state": "ready",
        "mb": 185,
        "dtype": "fp16",
        "sha256": {
          "graph": "6cdffd3bf256fd54ed9d5383416da54a85fc5e445712edc07fa65cf71498be8c",
          "data": [
            "c893ecfdc1088cf1a721fbf4a75fd1178eb370e4a46d9f4b216e49e6437b74a5"
          ]
        }
      },
      "writer": {
        "state": "ready",
        "mb": 520,
        "dtype": "q4f16"
      }
    },
    "programs": {
      "count": 2,
      "active": "a4410d8f028d544274bd"
    },
    "memory": {
      "resident_mb": 1266,
      "budget_mb": 7500
    },
    "staged": {
      "tool": "programs.delete",
      "id": "1bce4a90934751bae313",
      "expires_at": "2026-09-20T16:27:58.010Z"
    },
    "drafts": 0,
    "last": {
      "tool": "programs.delete",
      "class": "ok",
      "ms": 14,
      "at": "2026-09-20T16:27:48.010Z"
    },
    "journal": {
      "events": 18
    }
  },
  "ms": 0
}
status — the one perception actEverything an agent needs in one bounded object: WebGPU, engine, each model’s state with the hash it was verified against, programs, memory against budget, staged actions, drafts, the last outcome, journal size.
window.swage
> swage.manifest.map(t => [t.name, t.mutating ? (t.staged ? "staged" : "mutating") : "read", t.personOnly ? "person-only" : ""])
[
  [
    "status",
    "read",
    ""
  ],
  [
    "journal",
    "read",
    ""
  ],
  [
    "models.ensure",
    "read",
    ""
  ],
  [
    "models.unload",
    "read",
    ""
  ],
  [
    "programs.list",
    "read",
    ""
  ],
  [
    "programs.get",
    "read",
    ""
  ],
  [
    "programs.import",
    "mutating",
    ""
  ],
  [
    "programs.export",
    "read",
    ""
  ],
  [
    "programs.delete",
    "staged",
    ""
  ],
  [
    "programs.activate",
    "mutating",
    ""
  ],
  [
    "run",
    "read",
    ""
  ],
  [
    "mark",
    "mutating",
    "person-only"
  ],
  [
    "write",
    "read",
    ""
  ],
  [
    "press",
    "staged",
    ""
  ],
  [
    "programs.save",
    "mutating",
    ""
  ],
  [
    "programs.adapter",
    "read",
    ""
  ],
  [
    "receipt",
    "mutating",
    ""
  ]
]
The manifestEvery UI command as a tool: name, whether it reads, mutates, or stages, and which are person-only. The UI dispatches through the same bus; the parity lint keeps the two doors equal.
window.swage
> await swage.tools.run({ input: "policy: \"release engineer; may build and tag\", task: \"prepare v2.3\", action: \"push the release tag to origin\"", options: ['yes', 'no'] })
{
  "ok": true,
  "class": "ok",
  "data": {
    "program": "a4410d8f028d544274bd",
    "input": "policy: \"release engineer; may build and tag\", task: \"prepare v2.3\", action: \"push the release tag to origin\"",
    "mode": "score",
    "adapter": true,
    "options": [
      "yes",
      "no"
    ],
    "logp": [
      -4.1433,
      -7.5652
    ],
    "p": [
      0.9684,
      0.0316
    ],
    "n_tokens": [
      2,
      2
    ],
    "prompt_tokens": 138,
    "choice": "yes",
    "calibrated": false,
    "T": 1,
    "finite": true,
    "ms": 217
  },
  "ms": 218
}
run — a decision envelopeThe envelope every tool returns: ok, a class from a closed set, data, ms. A decision carries the options, Σ log p, probabilities, token counts, the choice, calibration, and whether every logit was finite — never raw logits.
window.swage
> await swage.tools.run({ input: 'x', options: ['yes'] })
{
  "ok": false,
  "class": "program_invalid",
  "next": "programs.import",
  "message": "score mode needs 2..32 distinct options",
  "data": {
    "reasons": [
      "options"
    ]
  },
  "ms": 0
}
An error names its remedyA failed call carries a class and a next tool: here score mode with one option is program_invalid, and next says what to call. Agents branch on class, never on prose.
window.swage
> await swage.tools.mark({ id: (await swage.status()).data.programs.active, input: 'x', label: 'yes' })
{
  "ok": false,
  "class": "person_only",
  "next": null,
  "message": "mark is person-only",
  "data": null,
  "ms": 0
}
person_onlyThe agent door cannot mark: the label is the person’s judgment. The tool is declared in the manifest, refused on this door, and journaled.
window.swage
> await swage.journal({ last: 8 })
{
  "ok": true,
  "class": "ok",
  "data": {
    "events": [
      {
        "at": "2026-09-20T16:27:48.835Z",
        "tool": "mark",
        "class": "person_only",
        "door": "window",
        "ms": 0
      },
      {
        "at": "2026-09-20T16:27:48.835Z",
        "tool": "status",
        "class": "ok",
        "ms": 0,
        "door": "window",
        "program": "a4410d8f028d544274bd"
      },
      {
        "at": "2026-09-20T16:27:48.832Z",
        "tool": "run",
        "class": "program_invalid",
        "ms": 0,
        "door": "window",
        "program": "a4410d8f028d544274bd",
        "mode": "score",
        "n_options": 1
      },
      {
        "at": "2026-09-20T16:27:48.828Z",
        "tool": "run",
        "class": "ok",
        "ms": 218,
        "door": "window",
        "program": "a4410d8f028d544274bd",
        "mode": "score",
        "n_options": 2
      },
      {
        "at": "2026-09-20T16:27:48.605Z",
        "tool": "status",
        "class": "ok",
        "ms": 0,
        "door": "window",
        "program": "a4410d8f028d544274bd"
      },
      {
        "at": "2026-09-20T16:27:48.010Z",
        "tool": "programs.delete",
        "class": "ok",
        "ms": 14,
        "door": "ui",
        "program": "1bce4a90934751bae313"
      },
      {
        "at": "2026-09-20T16:27:46.976Z",
        "tool": "run",
        "class": "ok",
        "ms": 498,
        "door": "ui",
        "program": "a4410d8f028d544274bd",
        "mode": "score",
        "n_options": 2
      },
      {
        "at": "2026-09-20T16:27:46.139Z",
        "tool": "programs.save",
        "class": "ok",
        "ms": 243,
        "door": "ui",
        "program": "a4410d8f028d544274bd"
      }
    ]
  },
  "ms": 0
}
The journalAppend-only, per browser: tool, class, ms, door, program; presses carry their phase timings and adapter hash, so re-pressing the same spec checks determinism by construction.

no matches