Skip to content

Getting Started

Page status: release-ready Source state: checked-example Applies to: Shepherd v0.2.0 Owner: @docs-system-owner (TBD) Validation: docs_src/quickstart/test_world_hero.py

Quickstart. This is the path that runs on the shipped wheel, offline. For the mental model, see the concepts. For exact APIs, see the reference.

Run one task, get its work back as a retained output — a proposal held beside your files — inspect it, and settle it. Deterministic, keyless, no network.

Install

pip install shepherd-ai

Shepherd requires Python 3.11+. OS-level grant enforcement is exercised on macOS (Seatbelt); on Linux, Landlock enforcement is container-gated today; Windows is unsupported — use WSL. (Platform notes)

Initialize a workspace

Shepherd runs inside an initialized workspace. Lead with shepherd init:

mkdir shepherd-demo && cd shepherd-demo
shepherd init

Run

Save this as hero.py in that directory and run python hero.py:

import shepherd as sp

workspace = sp.open(".")  # run `shepherd init` here first

# A task is a signature + docstring: the contract a sandboxed agent fulfils.
# The grant on `repo` is what lets it write the repository.
workspace.tasks.register_source(
    task_id="quickstart.write_note",
    module="quickstart_tasks",
    source_text='''
import shepherd as sp

def write_note(repo: sp.May[sp.GitRepo, sp.ReadWrite], topic: str,
               output_path: str, output_text: str):
    """Write one note about `topic` into the repository."""
''',
    entrypoint="write_note",
    may_default="ReadWrite",
)

run = workspace.run(
    "quickstart.write_note",
    repo=workspace.git_repo(),
    args={"topic": "shepherd", "output_path": "NOTE.txt",
          "output_text": "Hello from a Shepherd retained output.\n"},
    runtime={"provider": "static"},  # deterministic, offline; "claude" = live agent
)

output = run.output()                              # a proposal, held to one side
print(output.changeset().inspect()["changed_paths"])  # what it wants to change
print(output.read_text("NOTE.txt"), end="")           # read it before deciding
output.select()                                    # record your decision — or .discard()
workspace.close()

What happens, in order:

  • sp.open(".") opens the initialized workspace. (On an uninitialized directory it raises — run shepherd init first.)
  • register_source registers a task. The task is a signature plus docstring — the contract a provider-run agent fulfils. The grant on repo (May[GitRepo, ReadWrite]) is what would let it write the repository; the signature is the permission surface.
  • workspace.run(...) executes it as a retained run. provider: "static" is the deterministic offline provider, so this run is reproducible and free; "claude" runs a live sandboxed agent instead (needs the claude CLI and auth).
  • The work does not touch your files. It lands as a retained output; you read its changeset and contents first, then settle it — select(), release(), or discard() — exactly once.

Output

Executed against the shipped 0.2.0 wheel (this exact transcript is what the page's test asserts):

['NOTE.txt']
Hello from a Shepherd retained output.

Inspect the record

Every run leaves a durable trace you can read back from the CLI:

shepherd run list
shepherd run show --latest
shepherd run trace --latest --events
shepherd run changeset --latest

You can also fetch this same demo in script form with shepherd demo write quickstart > quickstart_demo.py, and a live-agent variant with shepherd demo write agent-task (see the README).

If it fails

  • WorkspaceControlError from sp.open(".") — the directory is not an initialized Shepherd workspace. Run shepherd init there first.
  • Ran the script twice in the same directory? The second run raises InvalidRepositoryStateError (readiness blocked by run-...) — the workspace still holds the first run's registration. Start from a fresh directory when repeating the walkthrough.
  • Looking for with sp.workspace(model=...): my_task(...)? That ambient direct-call shape is a Dataflow roadmap surface — it does not run on the 0.2.0 wheel. Retained runs, as above, are the shipped path.

Next