Repository navigation
Releases: weftgo/weft
Release list
weft v0.13.0
core v0.13.0
see CHANGELOG.md, 0.13.0 — 2026-10-10
weft v0.12.0 — phase 3 of the devtools plan: the panel, @weftgo/devtools, the scope header, the live grant
0.12.0 — 2026-10-09
Phase 3 of the devtools plan (the panel): @weftgo/devtools on npm,
scope detection (explicit, response headers through weft/scope, DOM
markers, the page URL, the fallback), the panel's host API, layout,
theme, keyed renderer, views, honesty and the Request tab, Studio's
Request pane, and the live grant. Tags core/v0.12.0 (the
weft.version literal only; core's API is unchanged since 0.10.1) and
v0.12.0 — a minor bump, as ?token= is refused and mount() may
return null (Changed — breaking, Changed — migration).
Added
- The panel's size:
studio/dist/panel/panel.jsships at 62,591 B
gzip (61.1 KiB, 18.9 KiB of headroom under the 80 KiB cap), the last
row of the append-only ledgerstudio/web/panel-budget.json; every
panel build prints the per-item table from it. The KiB figures in the
entries below are each item's delta, or the panel's size when that
item landed — intermediate, not the release's. - Review fixes (panel): the size table and
budget.test.tsmeasure
panel.jswith its version stamp normalized to the fixed-length
placeholder"v0.00.0"(normalizeStamp), so a version bump moves no
ledger byte; the panel finds its own<script>tag bydata-weft,
else by thesrcthat resolves to the bundle'simport.meta.url—
never by a genericdata-endpoint/data-tokenword, so a
third-party widget's tag ahead of it no longer becomes its
configuration; nothing renders after a disconnect (the tree's filter
debounce and "copied" timer are cleared, no observer on a detached
sentinel); the turn filter's prompts, the reported parked calls and
failures and the header rung's paths are cleared on every start and
capped (oldest first); the server'soverflowframe reopens a live
lane on its own bounded backoff (1 s, doubling while overflows repeat
within a minute, a minute at most) instead of at once; viewport
resizes are coalesced to one redraw per animation frame; with two
panels on a page only one (the global's, else the first connected)
answers Alt+W; external keys are looked up as own properties only
(weft.content: "constructor"is no mode, an unknown cause no
cause); adata-weft-scopemarker on or inside a
data-weft-untrustedelement is ignored, and the README says markers
must not appear in untrusted HTML. - Review fixes (npm):
@weftgo/devtoolspublishes public
(publishConfig.access), withprepublishOnlyrunning
npm-package.ts --check, which now also fails on a missingexports
ortypestarget, an unguarded panel import, or a README naming
another version (the README no longer hard-codes one);engines
(node >= 18),homepage,bugs,keywords, andtypesfor
./panel.js.mount()waits for<body>(called from<head>it
returns the element and appends it onDOMContentLoaded), is
idempotent (a second call reuses the element it made and applies the
new options) and returnsnullwithenabled: falseor on a server;
the root entry is import-safe without a DOM (ssr-guard.js/
ssr-unguard.jsaround thepanel.jsimport; every export a no-op);
enabledonmount()and the React/Vue/Svelte helpers;Position
is the panel's whole placement union (left-dock,top-dock,
bottom-dockadded) andmount()takesmode,pushandzIndex
(written asdata-mode,data-push,data-z-index). Breaking:
mount()returnsWeftDevtoolsElement | null. - Review fixes (Studio UI):
make devtools-vite-checkis pinned
—examples/devtools-vitenames vite 8.3.4 and jsdom 30.1.2 exactly
and commits itspackage-lock.json(installed bynpm ci; the packed
tarball goes in after,--offline --no-save, and stays out of
package.jsonand the lockfile) — and runs in CI (job
devtools-vite, afterstudio);check.tswaits for the panel's
/api/metarequest with a deadline instead of a fixed 300 ms and
gives the bundle'simport.metathe built module's URL. The run page
re-reads a finished run's spans for the invoke_agent span only after
a running→finished transition it saw (a run opened cold reads them
once). While a run runs, a request row ahead of its transcript batch
says "bytes when the transcript is read" (no_transcript), not the
gapbadge (messagesSent's new optionalrunning). The result-cap
badge shows the bytes cut (truncated · 2.0 KiB cut) and an unrun
call'smax_tokens · call never executed. A badge's reason and fix
are its accessible description (aria-describedbyto a hidden
element), said once; its name is the label. The Studio suites' real
sleeps are fake timers advanced past the 2 s poll or deadline-polled
conditions. - Review fixes (verification): imported through
@weftgo/devtools
(bundled into an app's chunk) the panel no longer takes the app's
entry<script>for its own tag — itsimport.meta.urlis the
chunk's — so the endpoint default stays the page's directory (it was
/assets/, with apanel-config.jsonasked there and the app tag's
data-*read as configuration): the package'sssr-guard.jsmarks
the import beforepanel.jsevaluates (ssr-unguard.jsremoves the
mark) and the element class'snpmEntrykeeps it, and under it rung 4
isdata-weftalone; the standalonepanel.jsstill matches its own
src.make devtools-vite-checkkeeps the app's entry tag in a
second variant (page/app/) and asserts the endpoint. The panel's
Request tab passesrunningtomessagesSent, so it draws the
neutralno_transcriptwhere the run page does (a parity fixture
pins it). A badge's reason and fix are inline visually hidden text
after the label on both surfaces (the panel's.weft-sr, the run
page'ssr-only) — part of its accessible name, replacing the
aria-describedbyabove;titlestays for the pointer. The overflow
backoff measures calm from the reopen, so a sustained overflow holds
at the minute cap. Alt+W prefers a live, page-mounted panel (the
global's if it is one, else the first connected one; the dormant or
self-mounted docks only when there is none), so markup a page adds
later can be toggled. A run opened cold within 30 s of its end (the
row'sfinished) polls its spans for the invoke_agent span inside
that window. - The devtools panel's Request tab (plan E1.2): the run page's
Request pane in the panel, one step at a time (J/K, the tab's step
buttons, a step card;⤢carries it) — the chips "changed by
PrepareStep", "prompt changed at this step", "overridden by
experiment" and "catalog changed at this step" from the request
record's hashes, the system prompt with its bounded diff (vs the
previous step; at the first step vs the registered instructions when
the panel can read/api/manifest), the messages sent (count · bytes,
the last three inline, the rest in a D4 JSON tree inside the tab), the tool
catalog (description, policy chips, schema tree), params with "adapter
default", tool choice, thinking, the attempts, a subagent call's child
request and the compaction marker. Every absent block is a badge; a
read-scoped token seeshiddenand nothing else, and asks for no
prompt. The panel gate checks the studio-local trim's chip and diff
live. +5.5 KiB gzip (estimate +4 KiB). Review fixes: a derived
prompt or catalog record (a body that did not parse) is badged
derivedand never diffed over, on both surfaces (promptTextsays
undefined for it); the manifest is read per endpoint and token, asked
again 30 s after a failure and once when it does not list the run's
manifest hash (a redeploy); a subagent's "read its turn" says when the
child's history is unreachable and hands off to Studio; the tab's step
is the one ⤢ carries and J/K start from, walking the steps the record
names too; a Studio that serves no request record isnot_recorded
with the new obsdb causenot_served(/api/meta's
capabilities_off.requestswords first); the panes share their words
throughlib/requests.tsand the stripped words of the tools route
(+0.6 KiB: the tab is +6.1 KiB, 0.1 KiB past half again its estimate). - The devtools panel's honesty (plan D5): every badge the panel
draws comes from the A3 table through one module,
src/panel/badges.ts(<span class="weft-badge" data-hole="…">, the
table's label, the reason and fix as its title — the run page's span;
badge(hole, note)is what the Request tab calls): on the turn's
header, step cards, tool calls (a result cap's cut istruncated,
causeresult_cap; an unrun call of amax_tokensstep is
max_tokens), compaction markers and request lines. The table's
causes (log_cap,result_cap,no_public_id,no_spans,
dev_token_only) joinlib/honesty.tsasCAUSES, checked against
the golden. The footer's content line ("content on · 2 events
shortened (24.6 KiB cut)", "content off · weft.Content(false)" /
"· otel.NoContent()") replaces the "content is stripped" suffix; turn
rows carry "scripted (0 tokens)", "fork of s_…#e_…" and "experiment
of t3" chips from the run row (its model,weft.session.forked_from,
weft.forked_from).parity.test.tsproves every hole of the table
shows on both the panel and the run page for the same run; a grep test
keeps hole words out of every other panel source. The panel's badge
attribute is nowdata-hole(wasdata-weft-hole), as the run page's. Review fixes: a
finished step no request row names isgapon both surfaces (one
reason,lib/requests.ts); the run page's result-cap badge is the
table's (truncated/result_cap,max_tokenswith no fix for an
unrun call;HoleBadgetakes acause); a badge's reason and fix
ride in its accessible text on both surfaces; the content line is said
only on evidence, andnonereads "captured none (weft.Content(false),
or no destination takes cont...
core v0.12.0 — the weft.version literal moves to v0.12.0
The loop module at v0.12.0: the version literal only; no API change (apidiff: no incompatible changes vs core/v0.11.0). See the framework release v0.12.0 and CHANGELOG 0.12.0.
weft v0.11.0 — phase 2 of the devtools plan: the weft command, weft dev, discovery, doctor
weft v0.11.0
Phase 2 of the devtools plan (start and find): the weft command,
weft dev, the port policy, discovery, the stable dev token, the
Agents page from runtime registrations, weft doctor, and the panel's
configuration ladder. Tags core/v0.11.0 (the weft.version literal
only; core's API is unchanged since 0.10.1) and v0.11.0 — a minor
bump, as studio/cmd is removed (Changed — breaking).
Added
-
Agents from runtime registrations (plan B4): Studio remembers
each runtime's registration manifest by (service, manifest hash), in
memory;/api/manifestserves it when noweft.jsonis configured
(the file still wins) and lists every source insources[]with
live; two services registering one agent name in different versions
both appear./api/metagainsmanifest_sources,capabilities_off
(why an option left a capability off) andmanifest_check.source/
differs; the Agents page, playground and debugger empty states show
the reason. -
The
weftcommand (plan B1,cmd/weft):go install github.com/weftgo/weft/cmd/weft@latestyields aweftbinary.
weft studio [--addr] [--db] [--token] [--manifest] [--open] [--no-playground]is setup B (whatstudio/cmdserved) with the
playground on (studio.Playground(true), inert until an app's
runtime connects;--no-playgroundturns it off), the manifest from
--manifest/WEFT_MANIFESTelse the nearestweft.jsonfrom the
working directory upward (one line says which, or that none was
found), and--open(default on when stdout is a terminal) opening
the UI with the token in the URL fragment. The Studio API over a
terminal:weft runs [--agent] [--since] [--failed] [--limit] [--json](GET /api/runs;--limit50 by default, and a limit
that hid runs says so on stderr),weft open <run id> [--open] [--with-token](prints the bare<url>/runs/<id>; the token goes
only to the browser, or to stdout on--with-token),weft export <run id> [--format json|jsonl|otlp]to stdout andweft export <run id> --wefttest <dir> [--test name] [--force](the wefttest fixtures
unzipped into<dir>/<name>/, wherewefttest.Replay(t, dir)reads
them; a non-empty target needs--force, which replaces its*.json
fixtures);weft doctor;weft version. The API clients never
follow a redirect. The API clients take
--url(WEFT_STUDIO_URL, defaulthttp://127.0.0.1:7331) and
--token(WEFT_STUDIO_TOKEN). Exit codes: 0, 1 a failure, 2 a
usage error. -
weft dev(plan B1.2, FEATURES D7):weft dev [studio's flags] [--no-watch] [--watch dir] [-- command…](defaultgo run .)
starts Studio in-process asweft studiodoes (same flags and port
policy) and runs the app withWEFT_ENV=dev(kept when already set
non-empty),WEFT_STUDIO_URL,WEFT_STUDIO_TOKENandWEFT_DB(the
Studio's SQLite file) set — plain variables the app can set itself.
The app runs in its own process group and restarts on a.gosave
(fsnotify, 300 ms debounce; SIGTERM, 5 s, SIGKILL); a build failure
waits for the next save;--no-watchexits with the app's code
(127 when it cannot start); a directory arriving with.gofiles
restarts too. Ctrl-C, SIGTERM and SIGHUP stop the app, then Studio
(Linux adds Pdeathsig forgo run; a SIGKILL ofweft devcan
still orphan the app's binary). Each start prints one line:
studio <url>[#token=…] · app pid <n> · runtime rt_… registered
(the token only when generated; "no runtime registered yet" after
5 s, then a later line). Reuse follows the port policy: without a
fixed token a running token-walled Studio is skipped for the next
port (plan B3's stable token changes this). The
discovery file is plan B3's.examples/studio-localruns under it:
withWEFT_STUDIO_URLset it listens on 8080, keeps its local sink
(otel.Local(""), explicit) and registers its runtime with that
Studio. -
make studio-binbuilds./weftfrom./cmd/weft(ignored by
git). -
Studio's port policy (plan B2,
internal/listen, wired into
weft studio):127.0.0.1:7331is the one default. On a busy port
the binary asksGET /api/metathere (bearer:--token/
WEFT_STUDIO_TOKENwhen set): a Studio on the same database file is
reused —studio already running at http://127.0.0.1:7331 (pid 1234), reusing, exit 0, no database or listener opened — and anything else (another
program, a Studio on another database, one whose meta this token
cannot read) moves Studio to the next free port in 7331–7340 with
one line naming the skipped address and why; the banner prints the
real address. All ten busy is exit 1 naming the range.studio.New
is unchanged: an embedded Studio is the app's own listener. -
WEFT_STUDIO_ADDR, the--addrmirror. Either pins the
address: busy is exit 1 with the address in the error — no probe, no
fallback. -
/api/metapid: the serving process's id, underdb.path's
guard (loopback with no Token, or the server token; never a panel
token). -
weft doctor [--url URL] [--token TOK](plan B5): checks a
running Studio and prints one line per check — reachable, token
accepted, the database's path and size, the content it stores,
connected runtimes (and, when none, what this shell'sWEFT_ENVand
WEFT_STUDIO_URLsay about why), the panel bundle's version, and
whetherweft.jsonis stale against the latest runs. Every line
reads a field ofGET /api/meta(internal/doctor.Linesis the
table); the flags mirrorWEFT_STUDIO_URL/WEFT_STUDIO_TOKEN. An
unreachable Studio is the first line within a 5 s timeout and exit 1;
a redirect is reported, never followed. -
weft studio --manifest path(default$WEFT_MANIFEST; the flag
wins): the app'sweft.json, read once at start and served as
studio.Manifest—/api/manifestand the doctor's weft.json check
in setup B. An unreadable file is a start error. -
/api/metaexplains itself:content(Studio's ingest policy,
"as_received", and the latest run's content mark —full,
stripped,noneorunmarked— with a note and the fix naming
otel.NoContent()orweft.Content(false)),pricing(false
until a pricing table exists),retention(null: none
configured),runtimes(runtimes holding a command stream now),
panel_version(the embedded/panel.jsstamp) and
manifest_check({agents, checked, stale}: each manifest agent's
hash against its latest run'sweft.manifest.hash;nullwithout a
manifest or for a panel token), andauth_required(whether a
studio.Tokenis configured).content.errorand
manifest_check.error(omitted when empty) report a read that
failed or a manifest that does not parse — logged through the
process'sslogdefault too — instead of reading as an empty
database. -
obsdb/sqlite:
(*DB).Path()— the database file's absolute
path (""for:memory:). -
The discovery file (plan B3,
internal/discovery):weft studio
andweft devwritestudio.json—{url, token, db, pid, started, version}, mode 0600, the bound port in it — to./.weft/when it
exists, else$XDG_RUNTIME_DIR/weft/, elseos.UserCacheDir()/weft/,
and remove it on a clean exit.otel.Install/otel.Startand
runtime.Installread it whenWEFT_STUDIO_URLis unset: an app
withdefer otel.Install()()exports to the running Studio (and its
runtime dials it) with no configuration, one INFO line naming the
Studio joined. The file is trusted only when its url is loopback, it
is fresh (pid alive, under 24 h) and, on unix, it is 0600 and the
reading user's; anything else is ignored at Debug and removed by the
next writer. A second Studio's exit restores the first's file; the
writer drops.weft/.gitignore(*) when there is none. An explicit
otel.Studio(...)orWEFT_STUDIO_URLswitches the read off;
WEFT_DISCOVERY=offturns it off;otel.NoEnv()ignores it with
the rest of the environment. -
A stable dev token per database:
<db>.tokenbeside the SQLite
file (.weft/weft.db.token), 32 random bytes base64url, 0600,
created on the first start and served by every later one, so the
token survives a restart and a second bare start's probe reuses the
running Studio (the probe sends it only to an address the user's
discovery file names).--rotate-token(weft studio,weft dev;
an action, no environment mirror) writes a new one. -
GET <base>/panel-config.json(studio):{endpoint, version, capabilities}for the devtools panel, answered to a loopback (or
AllowOrigins) Host and a same-origin,AllowOriginsor loopback
Origin only (loopback by the Host's rule —localhost,
*.localhost, 127.0.0.0/8,[::1]— even withAllowOriginsset) —
a 404 otherwise;/api/metalists the newpanel-configcapability. -
The devtools panel's configuration ladder (plan C2): each field
(endpoint,public-id,token,position,open,auto)
resolves on its own throughmount(opts)→ the<weft-devtools>
element's attributes →<meta name="weft:endpoint|public-id|token| position|open|auto">→ the panel's<script>tag (the running
classic script, else the first withdata-weft, anysrc) →
panel-config.jsonbeside the script (endpoint only, same origin
only, never a token; asked only when nothing above named an endpoint)
→ the script's own directory. A<weft-devtools>element, a
mount(opts)ordata-auto="false"with no Studio answering shows
one line,Studio not reachable at <endpoint> · retry; the dock the
script mounted by itself still removes itself silently. The rung
table is instudio/README.md.
Dependencies
github.com/fsnotify/fsnotifyv1.9.0 (framework module only, for
weft dev's watcher;coreis untouched).
Changed
runtime/examples/localserv...
weft v0.10.1 — the panel release asset script reads the one version
Fixed
- studio:
make studio-panel-asset(the devtools panel as a release
asset) read thestudio.Versionliteral that 0.10.0 removed and
failed; it reads the one version fromversion/version.gothrough
the same helper the panel build stamps from. Tagscore/v0.10.1(the
weft.versionliteral only) andv0.10.1.
The full 0.10.0 notes (the request record, the step and export routes, the honesty table) are on the v0.10.0 release; this patch only fixes the panel asset build and carries the same panel bytes.
weft v0.10.0 — the request record, Studio's step and export routes, the honesty table, one version from the module
The request record (ADR 0028): every model call's system prompt, tool
catalog, parameters and attempts recorded beside the transcript, read
back by Studio and the devtools panel with a closed table of honesty
badges; app logs, the step route, the export in four formats; one
version from the module. Tags core/v0.10.0 (compatible additions
only) and v0.10.0 (breaking in the pre-freeze layers listed below).
Changed — breaking
- One version, the module's. The new
github.com/weftgo/weft/version
package (standard library only) holds it:version.Versionis the
release tag,version.Runtime()reads the framework module's version
from the build info (the main module or thegithub.com/weftgo/weft
dependency, honouringreplace) and falls back toVersionunder
(devel).studio.Versionis nowversion.Version—v0.4.1→
v0.9.0— so/api/meta'sstudio_versionand the devtools panel's
embedded version (stamped fromversion/version.goat build) move
with the module. A panel built forv0.4.1refuses a Studio that
reportsv0.9.0as newer. /api/meta'sweft_versionis the framework module's build-info
version (version.Runtime()), no longer thecoredependency's;
inside the workspace it reads the tag instead of(devel).obsdb.DBgainsTranscriptBatches(ADR 0028 §8): a run's
messages records with what each stored — index, step
(weft.step.index, -1 when absent), input flag. A third-partyDB
reads pos, step, body and theweft.messages.inputattribute per
messagesrecord, returns them throughobsdb.DedupBatches, and
implementsTranscriptasobsdb.TranscriptBodies(batches). A
backend with no attribute column infers the input flag on index 0 and
setsTranscriptBatch.InputDerived./api/runs/{id}/transcriptrows carry what the record stored: the
storedindex, the storedstep(or-1with"badge": "not_recorded") and the storedinput("badge": "derived"where
the backend inferred it) — no longer derived from assistant-message
order. Playgroundtranscript_edits/from_stepvalidation and the
web client read the same stored step; only a batch without one is
placed by inference, marked derived.obsdb.DBgainsRequests,Prompt,ToolsandCatalogs
(ADR 0028 §10, the request record's read side). A third-partyDB
reads itsrequest,promptandtoolsrecords (stored under
(run, kind, index)) asobsdb.StoredRecords through
obsdb.RequestRecordOf,obsdb.PromptRecordOfand
obsdb.ToolsRecordOf, returns one tools record per hash (the lowest
index) fromCatalogs, and answers a missing hash with
obsdb.ExplainMissing.obsdb.RunRowgainsInstructionsHash,
CatalogHashandRequestCount, which a backend fills with the
larger ofrun_start's and theinvoke_agentspan's
weft.instructions.hash, request index 0'sweft.catalog.hashand
maxweft.request.index+ 1.obsdb/clickhouse's unreleased migration 0004 gained
weft_records.Input,Content,TruncatedBytes,SystemHashand
CatalogHash: a database
that applied 0004's earlier text (only a development build wrote one)
lacks them and must be recreated. ClickHouse now reads the transcript
input flag as stored; only rows written before the column read
TranscriptBatch.InputDerived.obsdb.DBgainsCompactions(ADR 0028 §8, plan A9): a run's
compactions asobsdb.Compaction— each run-scope view in index
order with its step, half-open range, hash and body, then thread's
session markers in emission order. A third-partyDBbuilds each through
obsdb.CompactionOf(from amessagesrecord whose
weft.messages.reasonis set, or a record of kindcompaction) and
orders them withobsdb.SortCompactions. ItsTranscriptand
TranscriptBatchesmust skip everymessagesrecord whose
weft.messages.reasonis set, and its messages count must not count
them (obsdb.Weft.Reasoncarries the attribute).obsdb.DBgainsOtherLogs(plan A7): a run's app log records —
the non-weft records (noweft.run.id) the writers keep beside
weft's, attributed to the run through the span they were emitted
under (its own spans and the non-weft spans below them, never another
run's) — as anobsdb.LogPageofobsdb.OtherLogs, paged by
obsdb.LogQuery(Frominclusive,Limit0 = 100 max 1000,
MinSeverityfiltering without renumbering), withPartial(the run
is running: lines under in-flight spans appear when those spans end,
and indexes may shift),Gap(lines naming a span never stored) and
Truncated(more thanobsdb.MaxLogCandidateslines in the run's
traces, counted before attribution). A third-partyDBimplements it as
obsdb.ReadOtherLogs(ctx, db, runID, q, candidates), where
candidatesreturns the firstlimitnon-weft records of the run's
traces within a time window, in time order.obsdb.HoleError.Kindgains"logs": a finished run
with no span has nothing to attribute through and answers
HoleNotRecorded.
Changed
- The system prompt and the tool catalog now reach content-on
destinations (otel.Local,otel.Studio) under the content policy:
Redact-able, capped withweft.content.truncated_bytes, dropped by
content-off destinations. ADR 0028 reverses the old stance that no
record carries the instructions text. An application whose prompt must
not leave the process redacts it (core.ContentPrompt) or turns
content off for that destination.
Added
-
The compaction marker on the run page and in the panel (plan
A9.2, ADR 0028 §8).GET /api/runs/{id}gainscompactions: each
compaction the run's records name, counts and hash only, never a
message body — a run-scope view{scope: "run", index, step, from_seq, to_seq, hash, replaced, entries}and thread's session
marker{scope: "session", hash, replaced, entries, tokens_before?, tokens_after?, reason};[]for a run that never compacted or was
written before A9 (the record is optional: no badge). A read-scoped
panel token reads it. The run page's step card whose request saw a
view draws "2 messages rewritten into 1 by PrepareStep" ("1 message
inserted by PrepareStep" when nothing was replaced) with the
compactedbadge; a session marker sits at the top of the run it is
filed under — "12 messages compacted into 2 · 8.1k → 1.2k tokens".
"show original" (collapsed, no fetch) expands a view's replaced range
[from_seq, to_seq)from the transcript route's growth records the
page already holds (seq = position in their concatenation); a range
that cannot be placed is thegapbadge. The replacement shows its
count — and, once the step route is loaded, the request's message
count — and says where its body is (the export's
compactions[].messages). The devtools panel draws the same marker:
session markers at the top of the turn, views on their step line. -
A run's app logs and its delta count in Studio (plan A7).
GET /api/runs/{id}/logs?from=&limit=&severity=, under a newlogs
capability in/api/meta, pages the app's own log lines (anslog
bridge or the OTel Logs API on the pipeline'sLoggerProvider) that
were emitted under the run's spans — a tool handler's lines are the
run's — in time order:{logs: [{index, time, severity, severity_number, body, attrs, span_id?}], next_from?};severity
keeps a level and above (trace…fatal, or 1–24).holeslists
every hole of the page (badge/reason/fixrepeat the first):
not_recordedfor a run recorded without a tracer,truncatedwhen
the run's traces hold more than 10 000 log lines in its window (the
cap applies before attribution: later lines of this run may be
missing),gapfor lines in the run's trace naming a span that is
not stored (they may be another run's). A running run's page carries
partial: trueand apartial_reason(lines under in-flight spans
appear once those spans end; indexes may shift) — not a hole.
App logs may carry anything the app logged, prompts included, so a
read-scoped panel token is refused them (403,badge: "hidden"); a
playground-scoped token, the server token and loopback read them. The
run row (runs,runs/{id}, sessions, the export) gains
delta_count, the streamed deltas counted and never stored. The web
client gainsfetchLogsand the types (no UI yet). -
Subagents on the page (plan A10).
GET /api/runstakesall=1
(every run, subagent children included — the same asparent=*; a
parent=<run id>beside it wins; a malformed value is a 400) beside
the existingparent=filter, whose absence keeps the list top-level
only. On the run page a step whose tool call started a child run
shows it as a nested row — agent, status, usage, its holes, a link to
its own page (from the run document's children, or the step route's
children[]when cached) — and opening it folds the child's steps
with the child's own request record, read by the child's id
(/api/runs/<child id>/requests, under therequestscapability:
the child's prompt, never the parent's; a read-scoped token sees
hidden). A call joins its child by the child's id, which names the
step (<parent>/<step>/<call id>— call ids may repeat across steps),
in the story and the trace view's call detail alike; a child id of
another form falls back to the first unlinked call with its
parent_call_id. The run document'schildren[]rows carry each
child's ownholes; a child's usage shows once it ended ("usage at
finish" while it runs, "—" beside the interrupted badge). The runs table is "top-level only" by default with a toggle
(?subagents=all) and a?parent=filter chip; a child row links its
parent. The devtools panel's subagent badge opens the child inline,
one level: its row (agent, status, usage),...
core v0.11.0 — the weft.version literal moves to v0.11.0
The weft.version literal only; core's API is unchanged since core/v0.10.1. Released with weft v0.11.0 (phase 2 of the devtools plan).
core v0.10.1 — the weft.version literal moves to v0.10.1
No API change over core/v0.10.0: only the weft.version literal every run stamps moves to v0.10.1, in lockstep with the framework's v0.10.1 (the panel release asset script fix).
core v0.10.0 — the reporting hook, the request record, compaction views, TTFT and latency
Compatible additions over core/v0.9.0 (the apidiff gate reports no incompatible changes): ReportFromContext/Reporter/AttemptInfo/RawPair (the reporting hook, ADR 0016's A8 note; mw.Retry and mw.Fallback report every attempt as an attempt span); the request record (ADR 0028: request, prompt and tools records with weft.instructions.hash on RunStart, weft.system.hash, weft.catalog.hash; ContentPrompt, ContentStop; Origin(name) for a tool's source); the run-scope compaction view record and (*Agent).LoggerProvider(); StepFinish.LatencyMS and TTFTMS with the answering model on the chat span. Nothing the model sees changes with recording on or off. Full notes: CHANGELOG.md, 0.10.0.