Skip to content

feat(jobs): long-running job substrate (Tier A milestone 1) - #83

Merged
shoom1 merged 2 commits into
developfrom
feature/job-control
Jun 14, 2026
Merged

feat(jobs): long-running job substrate (Tier A milestone 1)#83
shoom1 merged 2 commits into
developfrom
feature/job-control

Conversation

@shoom1

@shoom1 shoom1 commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Long-running job substrate — Tier A milestone 1

Implements §3.2 of the domain-tool-packages plan. A long-running job is a typed tool; the LLM only sees the tool, which calls an internal JobManager over pluggable execution backends. There is no generic job_submit and JobManager is never an LLM-facing tool.

What's here (all backend-agnostic; layers 1 + 3 of the design)

  • JobManager + JobBackend (tools/jobs/): one interface, two backends shipped — subprocess (detached, start_new_session; restart-safe completion via an on-disk exit_code sentinel written from a subshell; zombie reaping with a returncode fallback) and in-process (thread pool, for lighter work).
  • Persistence + reconcile: records under ~/.{app_name}/jobs/; on startup, non-terminal jobs are re-polled (a vanished process → unknown).
  • Concurrency: cap + queue (max_concurrent_jobs, default 4).
  • Tools: reference run_shell_job (long_running=True, capability longrunning.run_shell_job → default user-verify via the existing permission ASK flow) + observe-only job_status/job_result/job_logs/job_cancel/job_list (jobs.manage) that read/manage but never start jobs.
  • Wiring: @register_tool(long_running=…), JOB_MANAGER service key, base_manager job_manager property + _TOOL_SERVICE_MAP + lazy init branch, max_concurrent_jobs setting.
  • /jobs command: /jobs (running+queued), /jobs all, /jobs <id>, /jobs cancel <id>, /jobs clean.
  • Tests: tests/tools/test_jobs.py (15) — backends, cap+queue, cancel, persistence reload, vanished-process reconcile→unknown, clean, and the tools via the service registry.

Deferred (by design)

  • Milestone 2: harness "Jobs" UI monitor (background task showing live status; status-bar baseline).
  • Milestone 3: REST/cloud backends + first real domain long-running tools.
  • Phase 2: push/resume auto-ingest (the only orchestrator-specific piece).

Offline suite: 1552 passed, 5 deselected (llm), 0 failed.

shoom1 added 2 commits June 14, 2026 14:27
Typed long-running tools start detached work via an internal JobManager over
pluggable execution backends behind one JobBackend interface. The LLM only ever
sees the tool; JobManager is internal infrastructure (never an LLM tool) and
there is no generic job_submit.

- tools/jobs/backends.py: JobBackend + JobState; SubprocessBackend (detached,
  start_new_session, restart-safe on-disk exit_code sentinel via subshell, zombie
  reaping with returncode fallback) and InProcessBackend (thread pool).
- tools/jobs/manager.py: JobManager + JobRecord — persistence under
  ~/.{app_name}/jobs/, startup reconciliation, concurrency cap+queue.
- tools/jobs/tools.py: reference run_shell_job (long_running=True,
  longrunning.run_shell_job -> default user-verify) + observe-only
  job_status/job_result/job_logs/job_cancel/job_list (jobs.manage).
- registry: @register_tool(long_running=) flag on ToolDefinition.
- wiring: JOB_MANAGER service key, base_manager job_manager property +
  _TOOL_SERVICE_MAP + lazy init branch; max_concurrent_jobs setting.
- /jobs command (running+queued; all/<id>/cancel/clean).
- tests/tools/test_jobs.py (15 tests): backends, cap+queue, cancel, persistence,
  vanished-process reconcile, clean, tools via service registry.

Deferred: harness Jobs UI monitor (M2), REST/cloud backends + domain tools (M3),
push/resume auto-ingest (phase 2). Offline suite: 1552 passed.
…B_TOOLS=[job_status]

Addresses tool-sprawl: most agents now add just two job tools — their typed
long-running tool + job_status. job_status is enriched to also return the
result once the job is terminal, making job_result/job_logs redundant for the
LLM. JOB_TOOLS slimmed to [job_status]; the full set moves to opt-in
JOB_MANAGEMENT_TOOLS (which also powers /jobs). All five tools stay registered
and importable; listing/cancelling is normally a human action via /jobs.
@shoom1
shoom1 merged commit 10eda8e into develop Jun 14, 2026
@shoom1
shoom1 deleted the feature/job-control branch June 14, 2026 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant