the layer between your interface and the model
Context is a graph.
Not a window.
Ruxsh replaces the text blob above your model with a typed graph. Nodes are addressable, edges carry meaning, and context is fed only when the task actually reaches for it — across every agent and subagent you deploy.
Private beta. Tell us what you're building.
Everything above the model is still a text file.
Models got dramatically better. The layer feeding them did not. It is still string concatenation with a similarity search bolted on, and every failure below comes from that one decision.
A spec, a schema, a stale incident and yesterday’s transcript arrive as one undifferentiated stream. The model has no way to know which of them it is allowed to contradict.
Embeddings return the chunks that look most like the question. There is no way to say "this document is wrong now" — so the closest match wins, even when it has been superseded for months.
Every child gets a pasted transcript and re-derives what the parent already established. You pay for the same reasoning n times and get n slightly different answers.
One file. .rux
A .rux file declares context instead
of concatenating it. Every node is addressable and priced. Every edge says something the
runtime can act on.
It is a source file, so it diffs, reviews and versions like the rest of your repo — and it is generated for you the first time you point Ruxsh at a codebase.
- addressable
- every node has a stable path you can walk to, pin, or supersede
- priced
- nodes carry a token cost, so a walk can budget before it spends
- lossy on purpose
- a summary twin keeps expensive nodes cheap until they are needed
# graph.rux — context is declared, not concatenated.# Nodes are addressable. Edges are typed. Nothing is a blob. node spec/billing { source ./docs/billing/**.md cost 1.2k pin true # a constraint source: always resident} node code/checkout { source ./src/checkout/** cost 8.4k summary auto # collapses to 240t until the walk needs more} node incident/2291 { source linear:ENG-2291 ttl 14d # ages out of the graph on its own} # Typed edges. The traversal knows what each one means, so it# knows what to load, what to pin, and what to refuse to load. spec/billing constrains code/checkoutcode/checkout derives tests/checkoutincident/2291 supersedes spec/billing@v3tests/checkout cites spec/billingcode/checkout summarizes code/checkout#outlineSix kinds of edge. Each one changes what the model is allowed to see.
A knowledge graph with one generic related-to edge is just a slower vector store. The value is in the taxonomy: the runtime treats each kind differently during a walk.
B was produced from A.
The forward edge. Change a node and the runtime knows, exactly, which downstream nodes just went stale — no re-embedding, no similarity guess.
A bounds what B is allowed to be.
Invariants, schemas, policy, style rules. Constraints are pinned: they load with their target and are never the thing that gets summarised away to save budget.
A replaces B.
The edge that kills stale context. Once a node is superseded the traversal will not hand it to a model, even if it is the closest match in the whole graph.
B refers to A.
A weak, lazy edge. The cited node stays out of context until the model actually reaches for the claim — then it is resolved mid-turn and folded in.
A is a lossy view of B.
Every expensive node gets a cheap twin. The walk spends the summary first and expands to the full node only when the cheap version stops being enough.
A is the scope boundary for B.
The subagent edge. Forking on an "owns" edge gives a child a real view of the parent graph — same nodes, same versions, narrower horizon.
Agents, workflows and deployment are all the same language.
Rux is where you say what an agent may see, how work fans out, and where it runs. No YAML beside a framework beside a deploy config — one file, one mental model, one thing to review.
agent reviewer { model claude-opus-5 context ./graph.rux budget 32k # hard ceiling, enforced by the walk on pull_request { walk code/checkout -> derives -> * hold constrains # pinned for the whole turn defer cites # fetched only if the model asks emit review }}The agent never sees a prompt template. It gets a graph, an entry point, a traversal and a budget — so what lands in context is derived from structure, not from string formatting.
flow ship { reviewer -> triage triage -> fix | escalate fork 4 as auditors { scope owns(code/**) inherit constrains, supersedes # children start warm budget 8k each merge by consensus -> triage } on fail -> escalate}fork is the whole multi-agent story.
Children inherit the constraints and supersessions the parent already resolved, work inside
their own scope and budget, and merge back into the graph.
deploy ship { region auto scale 0..64 secrets from env trigger github:pull_request}Deployment is four lines in the same file as the workflow it deploys. Scale to zero between triggers; the graph is the only state that has to survive.
$ ruxsh deploy ./ship.rux ⠿ graph graph.rux · 412 nodes · 1,308 edges ⠿ resolve 6 edge kinds · 0 cycles · 0 orphans ⠿ agents reviewer, triage, fix, escalate ⠿ subagents auditors ×4 · scope owns(code/**) ⠿ deploy ship.ruxsh.dev · cold start 41ms ✓ live. 0 config files written.Or drive it from the code you already have.
Rux is optional. The runtime is a library too — and context is programmable at runtime, not frozen at build time.
// The runtime decides what each consumer sees,// per turn, from the edges — not from a template. const ctx = await ruxsh.open('./graph.rux'); await ctx.walk('code/checkout') .through('derives') .hold('constrains') // pinned .budget(32_000); // the walk stops itself // Override it wherever you disagree.ctx.edge('incident/2291', 'supersedes', 'spec@v3');Small enough to hold in your head.
Five declaration forms, six edge kinds, six walk verbs. That is the whole language — the entire surface grammar fits on one screen, and there is no hidden runtime configuration underneath it.
surface grammar
(* Rux — the complete surface grammar. Newlines terminate edges and steps; # starts a comment. *) program = { declaration } ;declaration = node | edge | agent | flow | deploy ; node = "node" path "{" { field } "}" ;field = ident value ; (* Edges are infix: subject verb object. *)edge = path kind path ;kind = "derives" | "constrains" | "supersedes" | "cites" | "summarizes" | "owns" ; agent = "agent" ident "{" { member } "}" ;member = field | handler ;handler = "on" event "{" { step } "}" ;step = "walk" selector | "hold" kind { "," kind } | "defer" kind { "," kind } | "drop" selector | "expand" selector | "emit" ident ; flow = "flow" ident "{" { clause } "}" ;clause = route | fork | handler ;route = ident "->" target { "|" target } ;fork = "fork" int "as" ident "{" { field } "}" ; deploy = "deploy" ident "{" { field } "}" ; selector = path [ "->" kind "->" reach ] ;reach = path | "*" ;path = segment { "/" segment } [ "@" version ] [ "#" fragment ] ;segment = ident | "*" | "**" ;what a walk actually does
Six stages, same order every turn. Nothing here is heuristic — each stage is driven by one edge kind, which is why the same graph produces the same context twice.
- 01 resolve
The entry selector expands to a node set. Nothing is read yet — this stage only decides what is reachable.
- 02 prune
Anything on the target side of a supersedes edge is removed. A stale node cannot re-enter later, whatever it costs or however well it matches.
- 03 pin
Every constrains neighbour of the surviving set loads at full fidelity and is marked non-evictable. Constraints are charged to the budget first, on purpose.
- 04 spend
The remaining budget goes to the derives frontier, breadth-first, highest weight first. This is the only stage that competes for tokens.
- 05 collapse
Anything that no longer fits swaps for its summarizes twin. A node is never truncated mid-sentence — it degrades to a view you wrote or the runtime generated.
- 06 defer
Each cites edge becomes a callable handle rather than text. The model spends tokens on a citation only in the turn where it actually follows one.
reference
Five top-level forms. There is no sixth — everything else is a field on one of these.
| form | declares | notes |
|---|---|---|
| node <path> { } | a unit of context | The only thing that costs tokens. Addressable by path. |
| <path> <kind> <path> | a typed edge | Infix, one per line. No block, no properties — the kind carries the meaning. |
| agent <name> { } | a model with a horizon | Binds a graph, a budget and one or more event handlers. |
| flow <name> { } | how agents compose | Routes, forks and failure paths between agents. |
| deploy <name> { } | where a flow runs | Region, scale, secrets, trigger. Lives in the same file as the flow. |
Every field is optional. A node with only a source is valid — the runtime infers the rest.
| field | type | effect on the walk |
|---|---|---|
| source | glob | uri | Where the content comes from. Files, globs, or a connector uri like linear:ENG-2291. |
| cost | tokens | Measured on first read, then cached. The walk subtracts it from the budget before loading. |
| summary | auto | path | Declares the cheap twin. auto generates one; a path points at a node you wrote yourself. |
| pin | bool | Resident for every walk that touches this subgraph. Survives budget pressure. |
| weight | 0.0 – 1.0 | Tie-breaker when two frontier nodes cost the same. Defaults to 0.5. |
| ttl | duration | The node leaves the graph when it expires. Incidents and tickets want this; specs do not. |
A handler body is an ordered list of these. They run once per turn, in the order written.
| verb | takes | what it does |
|---|---|---|
| walk | selector | Sets the entry point and the traversal. Everything else refines the result. |
| hold | edge kinds | Pins those neighbours at full fidelity for the whole turn. |
| defer | edge kinds | Turns those neighbours into handles the model can resolve mid-turn instead of loading up front. |
| expand | selector | Forces summarised nodes back to full text, budget permitting. |
| drop | selector | Removes a subgraph from this turn regardless of what the edges say. |
| emit | name | Names the output so a flow can route on it. |
Paths address nodes; the operators turn one address into a set.
| syntax | reads as | example |
|---|---|---|
| a/b | exact node | code/checkout |
| a/* | children, one level | code/* |
| a/** | the whole subtree | code/** |
| @v | a pinned version | spec/billing@v3 |
| #frag | a named twin or region | code/checkout#outline |
| x -> kind -> * | traverse one edge kind outward | code/checkout -> derives -> * |
| owns(sel) | a fork boundary | owns(code/api/**) |
n subagents. One graph. Nothing to configure.
A subagent does not receive a copy of the transcript. It forks along an owns edge and gets a scoped view of
the same graph — same nodes, same versions, narrower horizon, its own budget.
No vector store to provision, no chunk size, no top-k, no re-ranker, no eval harness for any of it. Those are all workarounds for context being text.
You do not template a context block. The walk decides what enters the turn, in what order, at what fidelity, against a budget it enforces itself.
The graph is the memory. Nodes age out on a ttl, get replaced by supersedes, and collapse to summaries under pressure — without a second system.
The ones we'd ask too.
No. Retrieval ranks chunks by how much they look like your query. A .rux graph does not rank anything — it walks edges that were declared, so what arrives in context is what the task structurally depends on, not what happened to embed nearby.
The practical difference shows up on negatives. RAG has no way to express "this document is wrong now." A supersedes edge does, and the traversal honours it. There is no embedding model, no chunk size, no top-k and no re-ranker in the loop.
That is the normal case, and it is the entire point. The graph is not the context — it is the map the runtime walks to build the context. A walk starts at an entry node, spends its budget on the highest-value edges, uses summarizes twins for anything expensive, and stops.
A million-token graph and a 32k budget is an ordinary configuration. Nodes that are never traversed cost nothing.
No. Point Ruxsh at a repository, a docs tree or an existing agent and it emits the graph itself — nodes from files and services, edges from imports, references, ownership and history.
Rux is the escape hatch, not the on-ramp. You write it when you disagree with the inferred graph: to pin a constraint, to declare that an incident supersedes a spec, to draw a scope boundary a static analyser could not have found.
Any of them. Ruxsh sits between your interface and the provider, so the model receives an ordinary request — it just receives a far better assembled one. Swapping providers is a one-line change and does not touch the graph.
Multi-model flows are the same mechanism: a cheap model can walk a wide scope and hand a narrow, warm subgraph to an expensive one.
There is no vector store to provision, no chunking strategy, no retrieval parameters, no prompt assembly layer and no memory service. Those are all consequences of treating context as text, and the graph removes the need for them.
Install it, point it at your source, deploy. Everything after that is optional Rux you write when you want different behaviour.
They do not get a copy of the transcript. A subagent forks on an "owns" edge and receives a scoped view of the same graph — same nodes, same versions, a narrower horizon and its own budget.
Because it is one graph rather than n transcripts, children start warm instead of re-deriving what the parent already established, and their results merge back as nodes the parent can walk.
Stop packing a window. Start walking a graph.
We're onboarding a small number of teams running real multi-agent workloads. Bring a codebase that already breaks your context budget — that's the interesting case.