Repository navigation
Job index: a job you can name, find and read back (plans/job-index.md) - #134
Merged
Merged
Conversation
…x.md, fs half) A job you can name, find and read back. The record (jobs.ts) gains a title, who started it and one line per run; the RUNNER writes the line at run.start through ctx.services.jobs.recordRun (children with parentRunId, a resume records nothing), carrying the launch's `title` — a launch-level field beside `job` and `callback` on POST …/run and strut.run, 400 without a job. The sweep keeps a record that has runs. A session's turn line records the job it was made under (SessionInfo.jobs). The read side is new: src/job-index.ts (createJobIndex over the run store, the session store and dataDir) — list (newest-used first, `q` through the workflows' matcher over the title and current deliverables), get (runs with status, threads by the turn line's job or by name, holds, files, and the artifact FOLD: successful top-level runs' artifacts[] newest first, the first of each id winning, resolved like …/runs/:runId/artifacts; a sealed workflow's run shows its status and nothing more; `text` = the latest reply) and read (one file, text capped head+tail, an image as bytes). createStrut builds it into services.jobs; GET /jobs[?q=] and GET /jobs/:id are thin over it, as are three lib steps the seed can grant: job/list, job/get (adds `dir`), job/read (an image is shown to the model via withMedia). Also: src/jobs.test.ts was never in the npm test list; it is now (29 tests, 7 new). Specs: API.md, AGENTS.md, the plan's status.
… from each run (plans/job-index.md §6, graph half) Two attributes and one node type. `job: ?string` on StrutRun and StrutAgentSession, stamped by the projector from run.start.job, so "everything in job X" is one match. `StrutJob` (exact_key on the job id — ids hold `/` and `-`; indexed title + summary; last_used_at, since updated_at is a generic node property) is upserted from the job index's `get` on every run of the job — title from the record, summary = each current deliverable as `title — summary` then the latest reply, capped at 2000 — with `IN_JOB` from the run. The run-end hook hands `services.jobs` to projectRunOnce; `graph/project` builds a job index over its dataDir; projectRun / projectRuns / projectAll take an optional JobReader, and a bare caller writes no job node. No StrutArtifact node (ruling 5). Live tests: a pure projection case, projectRun with a fake reader (one node, two edges, nothing without an index or a record), and the hook through createStrut (title, the fold's order, a plain run untouched); the schema/ontology count pins move from 9 types / 15 edges to 10 / 16.
Evanfeenstra
added a commit
to stakwork/stakgraph
that referenced
this pull request
Oct 9, 2026
…ad; bump strut (#1755) Bump strut to 58b7192 (stakwork/strut#134: plans/job-index.md built — a job you can name, find and read back; `title` on the launch body, one run line per launch on the job's record, GET /jobs[/:id] with the artifact fold, StrutJob in the graph). No dependency changes: the pin alone. The `job` seed grants the three reads in params.tools, between the meta/* tools and pod/*: job/list (earlier jobs by words — a title, or what one delivered), job/get (what one produced, its files with their paths, its threads), job/read (one of its files; an image the agent then sees). One paragraph in params.system says when to use them — a message that refers to earlier work — and the `Job` Concept page carries the same rule, kind-agnostic. The smoke expects the new tool list and now checks every granted tool (bar a glob) is in the registry, so a stale pin fails there instead of warning at run time. seed.ts's description and lab AGENTS.md updated. Not here: hive's `title` beside `job` on the launch body (it still rides on `input`, which the seed strips) — a one-line hive change.
Evanfeenstra
added a commit
to stakwork/hive
that referenced
this pull request
Oct 9, 2026
Strut's job index (stakwork/strut#134, plans/job-index.md) names a job by `POST …/run { job, title }` — a launch-level field like `job`, recorded on the job (its index, its StrutJob node), never on the run. Hive had the title in hand on every job turn but sent it only on `input`, where the `job` workflow's input block strips it, so every job on a swarm was titled by its id. `dispatchStrutRun` takes `title?` and puts it on the body only with `job`; `launchJobTurn` passes it beside `job: jobId`, and keeps the copy on `input` for the reply's header. Tests: the launch body carries it with a job, never without one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds
plans/job-index.mdas its §9 lays out: two commits, the filesystem half standing alone, then the graph. Rulings 1–7 as proposed;StrutJobwithoutStrutArtifactto start.The record (
src/jobs.ts):title,createdBy,createdAtand one line per run. The runner writes the line atrun.startthroughctx.services.jobs.recordRun— every launch site passes through there, children withparentRunId, a resume records nothing — carrying the launch'stitle: a launch-level field besidejobandcallbackonPOST …/runandstrut.run(400 without a job;inputwould strip it, and strut has to write it without knowing the workflow). The sweep keeps a record that has runs. A session's turn line records thejobit was made under (SessionInfo.jobs).The index (
src/job-index.ts, new):createJobIndex({ dataDir, store, sessions, sealed })→list(newest-used first;qthroughsrc/search.tsover the title and current deliverables),get(runs with status, threads by the turn line's job or by name, holds, files, and the artifact FOLD — successful top-level runs'artifacts[]newest first, the first of each id winning, resolved like…/runs/:runId/artifacts; a sealed workflow's run shows its status and nothing more;text= the latest reply) andread(one file, text capped head+tail, an image as bytes).createStrutbuilds it intoservices.jobs;GET /jobs[?q=&limit=]andGET /jobs/:idare thin over it, as are three lib steps the seed can grant:job/list,job/get(addsdir),job/read(an image is shown to the model viawithMedia).The graph:
jobonStrutRun/StrutAgentSession; oneStrutJobper job (exact key on the id; indexed title + summary of deliverables and latest reply), upserted from the index in the run-end hook and bygraph/project, withIN_JOBfrom each run.Deviations from the plan text (all simplifications, recorded in the plan's status): one write instead of two (
recordRuncarries the title; nodescribe); a folded ref carriespathandjob/getaddsdir, instead of an absolutefile;SessionInfo.jobsonly when a turn carried one;last_used_atinstead ofupdated_at(a generic node property the seed refuses).Also:
src/jobs.test.tswas never in thenpm testlist; it is now.Tests: 1415 offline (29 in jobs.test.ts, 7 new), 243 live graph (3 new) — all green locally. Docs:
specs/API.md,AGENTS.md, the plan.Next, outside strut: the mcp seed's
params.tools(+ a system line) and hive'stitleon the launch body besidejob.