SkillWeave v1.3.5
SkillWeave 1.3.5 does two things: it makes the runtime contracts from 1.3.0
hold what they promised, and it adds a routing layer that lets you drive
SkillWeave from one agent tool while the work runs in another.
Run it from one tool, execute it in another
Until now, the model that executed your work was whichever model the tool you
happened to be sitting in provided. If you plan in Codex and want the work done
by a different model, that was a manual affair.
1.3.5 makes both choices explicit and separate:
name: nightly
tier: balanced # intent, not a model name
roles:
ops:
model: sonnet
tool: { name: opencode, launch_command: "opencode run" }
reviewer:
model: gpt-4o # no tool: runs where you are
observer:
model: haiku
tool: { name: kilo, launch_command: "kilo exec" }
limits:
timeout: 600
max_retries: 2
min_models_required: 2A role with a target tool is dispatched there. A role without one runs in
place — staying inside your current harness is a first-class configuration,
not a fallback. Tiers name intent (fast, balanced, deep) and are resolved
to concrete models through Faigate, so a profile stays valid when the models
behind it change.
Three routing modes, all declared rather than inferred:
pinuses the named profile and decides nothing. An operator's override
is never silently improved upon.autoderives the tier from task complexity.hybridletsautodecide within bounds you declare — a floor tier, a
ceiling tier, and per-role pins. Any bound that moved the decision is
recorded as an adjustment, so the log never shows a tier nobody chose.
Every decision keeps requested and resolved apart: the mode, the profile, the
tier, the input that drove it, each adjustment, and what Faigate actually
returned. A later reader can tell what ran, not merely what was asked for.
A scheduler and a real runner
DagScheduler turns a task graph into batches. It rejects cycles by name
rather than dropping them, enforces max_parallel, and refuses to release the
dependents of a failed gate. It starts no processes and knows nothing about
runners — that separation is enforced by a test.
RunnerAdapter starts actual processes. Output is bound to the run as
ArtifactReceipt evidence rather than free text, exit codes are distinguished
from signals, cancel kills the whole process group and proves no descendant
survives, a timeout is a defined state rather than an unbounded wait, and a
worker that dies without a result is a failure with a message rather than a
silent success.
Write scopes are now claimed and released rather than merely checked, and the
claim is persistent. Overlap is decided on resolved absolute paths, so two
lanes that would write the same file never share a parallel batch.
Eight contracts that did not hold
These existed in 1.3.0 and looked correct. Each fix below ships with a test
that fails against 1.3.0 and passes here.
- Compare-and-swap detected no conflicts. The guard read
connection.total_changes, which is cumulative per connection and therefore
never differs between two reads. Every stale write reported success. It now
readsrowcount. - Journal sequences collided under concurrency. Allocation and insert are
now one transaction. Eight writers appending two hundred entries previously
persisted thirty-three. - The authority guard failed open. An unknown action returned
True. It
returnsFalse, and an undeclared role holds no capability at all. - Preflight validated part of the envelope, and compared string prefixes
where it meant resolved paths. - Checkpoints, handoffs and evidence lived in process memory and did not
survive a restart. They are persisted in the same store as runs and
transitions. - The state vocabulary disagreed with its own schema.
busy_timeoutwas never set explicitly. The value does not change
behaviour —sqlite3.connectalready defaults to 5000 — but a
concurrency-critical property should not depend on a library default nobody
chose, and a caller supplying their own connection could silently drop it.executor.execute_stepnever executed anything. It issimulate_step.
Upgrading
cap update LangeVC/skillweaveThe thirteen bundled skills stay at 1.3.0. None of them changed in this
release — only the runtime and the new routing layer did, and the bundle
version moves because its composition did. If your tooling expects bundle and
member versions to match, that assumption does not hold and was never intended
to: a bundle can ship a new composition of unchanged parts.
skillweave.routing and skillweave.runtime are not exported from the package
root and are reached by explicit submodule import. Treat them as evolving.
Compatibility
No breaking changes to the thirteen skills or their SKILL.md surfaces. The
runtime repairs change behaviour in the direction of the documented contract:
if you were relying on a compare-and-swap that never detected conflicts, or on
an authority check that returned True for unknown actions, that reliance was
on a defect and it is gone.
Requires Python 3.9+. Faigate is optional — routing profiles that pin concrete
models work without it.