Skip to content

Source workspaces

Many agent tasks operate on a related collection of files rather than one API record. Source workspaces let a Mesh inspect, execute, and propose changes over that collection without adding another persistence tier. The source may be a code repository, local project tree, exported archive, document collection, object-storage prefix, model bundle, dataset or build artifact.

BlobStorage remains the durable byte store. A SourceSnapshot is an immutable manifest of paths and content-addressed blobs. A SandboxBinding projects that manifest into a temporary CoderSandbox filesystem for one claimed step. A WorkspaceDelta stores only the step's accepted changes back in BlobStorage.

flowchart LR
    P[Source system] --> A[Trusted SourceAdapter]
    A --> S[SourceSnapshot]
    S --> B[BlobStorage]
    B --> W[Ephemeral SandboxBinding]
    W --> E[Inspect, build, test, edit]
    E --> D[WorkspaceDelta]
    D --> B

Universal workspace contract

Adapters own source-specific acquisition. JarvisCore owns everything after that boundary: immutable persistence, integrity verification, isolated per-step materialization, direct workspace tools, copy-on-write deltas, conflict detection and cleanup. Adding a new source type does not create a new execution model.

When workspace_required is true, the Mesh resolves source identity before planning. A caller may supply workspace_source explicitly through an API or CLI. Otherwise, the Mesh uses its planning model to extract only the source identity explicitly named in the goal, constrained to workspace_source_catalog and registered adapters. Adapter validation remains authoritative. Missing or ambiguous identity fails before goal registration, which prevents a source-backed Mesh from silently degrading into prompt-only analysis.

This resolution is internal to Mesh execution. General chat or task interfaces do not need provider-specific controls. A product declares trusted source types and users continue to state the source in the task naturally.

Snapshot limits, allowed commands, command timeouts and build-cache environment in caller context are ignored. Configure them on Mesh; they are execution authority, not user intent. Cache paths are node-local and should be writable by the Mesh worker. Only recognized package-manager cache variables are admitted; the parent process environment and secrets are not inherited.

GitHub reference adapter

GitHub is the first built-in adapter and demonstrates the universal contract for a remote authenticated source. Its OAuth app and account must be connected through Nexus.

from jarviscore import Mesh

mesh = Mesh(config={
    "nexus_enabled": True,
    "workspace_required": True,
    "workspace_snapshot_limits": {
        "max_files": 2_000,
        "max_total_bytes": 50 * 1024 * 1024,
        "max_file_bytes": 5 * 1024 * 1024,
        "concurrency": 8,
    },
    "workspace_allowed_commands": ["cargo"],
    "workspace_command_timeout_seconds": 600,
    "workspace_command_environment": {
        "CARGO_HOME": "/var/cache/jarviscore/cargo-home",
        "CARGO_TARGET_DIR": "/var/cache/jarviscore/cargo-target",
        "RUSTUP_HOME": "/opt/rustup",
    },
})

# Add capability-addressed peers, then start the Mesh.
await mesh.start()
result = await mesh.execute_goal(
    "Inspect, test, and propose a verified repair.",
    context={
        "workspace_source": {
            "provider": "github",
            "locator": "owner/repository",
            "revision": "main",
        }
    },
)

The adapter resolves revision to an immutable commit before planning. The workflow context receives only compact source metadata and a BlobStorage manifest reference, never repository contents or credentials.

Step isolation and deltas

Each claimed step gets a fresh materialization of the immutable snapshot. Dependency deltas are applied before execution. Successful local changes are exported under:

workflows/<workflow-id>/workspace_deltas/<step-id>/

Parallel branches may change different files. If two dependency branches change the same path to different content, JarvisCore rejects the merge instead of choosing one silently. Runtime and build directories such as .tmp, output, target, node_modules, and .venv are excluded from deltas by default.

Final-response steps consume prior artifacts and do not materialize the source again. Bindings clean up after success, failure, or cancellation.

If a step exhausts one bounded execution epoch without completing, JarvisCore exports that epoch's partial delta before releasing the claim. The next epoch restores both the Kernel checkpoint and the same-step delta. This means an agent can inspect in one epoch, edit in another, and complete later without losing the file state or the original mutation receipt. The final delta remains cumulative from the immutable source snapshot.

Coder workspace tools

Coder receives six direct tools when a workspace is attached:

Tool Purpose
workspace_list List bounded file or directory metadata.
workspace_read Read a bounded UTF-8 line range.
workspace_search Search text and return path/line evidence.
workspace_write Create or fully replace one bounded UTF-8 file. The supplied content is the complete final file.
workspace_edit Replace an inclusive line range in an existing UTF-8 file after matching the sha256 returned by workspace_read.
workspace_run Run a trusted allow-listed command in a workspace directory.

These tools avoid generating Python merely to inspect or author files. Agents should use workspace_write for new fixtures and complete-file replacement, never for a partial source edit. Existing source files should be read first and changed with workspace_edit; a stale source hash returns a conflict instead of overwriting newer content. Path resolution rejects traversal outside the workspace. Both write tools produce WorkspaceMutation receipts. Command permissions, timeout and cache environment extend the existing CoderSandbox policy only through trusted Mesh configuration. A command timeout is returned as typed evidence and does not terminate the workflow.

Storage and distributed execution

Content-addressed file blobs are reused across repeated snapshots of the same source and immutable revision. Hash and size checks run during hydration.

Local BlobStorage is node-scoped. A workflow using it is pinned to the node that materialized the snapshot. Configure a shared BlobStorage backend for cross-node claims.

Large sources

Every adapter must reject sources beyond trusted limits. This is deliberate: an unbounded collection must not consume arbitrary memory, API quota, disk or model context. Large-source adapters may use sparse selection, pagination, streaming or provider-native manifests while returning the same SourceSnapshot contract.

The built-in GitHub adapter uses recursive tree and Git blob APIs and rejects a truncated tree. A future object-store adapter may paginate keys; an archive adapter may stream entries; a dataset adapter may capture a selected manifest. The execution and delta layers do not depend on those acquisition choices.

Build a source adapter

An adapter implements one provider-neutral protocol:

from jarviscore import SourceAdapter, SourceRef, SourceSnapshot


class ArchiveSource(SourceAdapter):
    async def capture(self, source: SourceRef) -> SourceSnapshot:
        ...

The adapter receives source identity and returns an immutable snapshot created through the BlobSnapshotStore supplied by the application. It owns:

  • validating provider-specific locator and revision syntax;
  • resolving mutable revisions to immutable identities;
  • reading source bytes through the appropriate credential boundary;
  • enforcing provider-specific completeness, such as truncated-tree detection;
  • applying trusted snapshot limits before unbounded hydration.

The adapter does not own sandbox creation, command execution, dependency deltas, merge conflict decisions or cleanup. Those remain shared JarvisCore behavior.

Before planning, JarvisCore validates every adapter result against the requested provider, locator and revision, reloads its persisted manifest from the Mesh's BlobStorage, and verifies every blob size and hash. An adapter cannot return an in-memory or foreign-store snapshot and still enter the DAG.

Use these public failures:

Error Meaning
SourceContractError The request or adapter result violated source identity or response shape.
SourceIntegrityError The persisted manifest or source bytes failed integrity validation.
SnapshotLimitExceeded Trusted materialization limits rejected the source.
GitHubSourceRequestError A GitHub request failed; status and bounded provider detail remain evidence, not routing decisions.

New adapters should reproduce the cases in tests/test_source_adapter_contract.py: valid persisted capture, identity preservation, rejection of foreign manifests, and rejection of corrupted blobs. Provider tests should additionally cover mutable-ref resolution, cache reuse, limits, malformed responses and executable file modes.

For natural-language entry points, describe custom providers in trusted Mesh configuration:

mesh = Mesh(config={
    "workspace_required": True,
    "workspace_source_adapters": {"archive": archive_adapter},
    "workspace_source_catalog": {
        "archive": {
            "description": "A named source archive resolved by the application",
        },
    },
})

workspace_source_resolver may override model-based identity extraction with a trusted callable. Its result is still constrained to the catalog and passes the same adapter and snapshot validation.

Authority boundaries

  • Source capture is read-only acquisition through the adapter's trusted access boundary. The built-in GitHub adapter uses Nexus; local or embedded sources may require no credential service.
  • Workspace mutation is local copy-on-write work and remains a proposal.
  • Publishing changes back to any source system requires a separate capability and policy decision; a workspace adapter grants no publication authority.
  • Source credentials never enter the snapshot, BlobStorage, prompt, or sandbox.