Skip to content

feat(sdk-python): first-class spec.git helper for durable workspaces#823

Merged
stubbi merged 4 commits into
mainfrom
feat/python-spec-git-619
Jul 10, 2026
Merged

feat(sdk-python): first-class spec.git helper for durable workspaces#823
stubbi merged 4 commits into
mainfrom
feat/python-spec-git-619

Conversation

@stubbi

@stubbi stubbi commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Thinking Path

  • Mitos boots Firecracker microVMs and forks them via copy-on-write snapshots, exposed through CRDs (SandboxPool, Sandbox, Workspace) in group mitos.run/v1.
  • This change is in the Python SDK (sdk/python), the client for both the cluster and sandbox-server paths.
  • A durable Workspace declares, via spec.git (the mitos.run/v1 WorkspaceGit), the repo paths that get version history and the fork-and-merge rendezvous remote. Until now the SDK had no first-class way to set spec.git, so the background_agent example patched the Workspace CRD by hand through the raw kubernetes client.
  • The Experience-is-DNA principle says every user-facing surface avoids dead ends and keeps a simple surface with depth one click down; a hand-rolled CRD patch in a shipped example is exactly the dead end to close, and this is the residual of Use-case example and template repo (best-of-N, RL/SWE-bench, background agent, code interpreter) #313 tracked as Python SDK: first-class spec.git helper for cloning a repo into a sandbox #619.
  • This pull request adds mitos.git(...), a pure spec-construction helper that builds spec.git declaratively, plumbs it into AgentRun.create_workspace(name, git=...) and Workspace.set_git(...), and simplifies the background_agent example to use it.
  • The benefit is a declarative, validated, LLM-legible way to declare workspace git paths (and an optional push-credentials reference) instead of hand-writing a CRD patch, with the token never entering the SDK.

Linked Issues or Issue Description

Closes #619

What Changed

  • Add sdk/python/mitos/git.py: GitSpec dataclass plus the mitos.git(paths, *, credentials_secret=None, credentials_username=None) factory, which validates arguments and renders the mitos.run/v1 spec.git JSON. Fail-fast LLM-legible errors: invalid_git_paths (empty or blank path) and invalid_git_credentials (malformed secret ref, or username without a secret). A coerce_git normaliser accepts a GitSpec or a bare list of paths.
  • Plumb git= into AgentRun.create_workspace(name, git=...) so the workspace is created with spec.git already set; omit the key entirely when git is not passed.
  • Add Workspace.set_git(...) to declare spec.git on an existing workspace first-class, replacing the raw patch_namespaced_custom_object idiom.
  • Export git and GitSpec from the mitos package.
  • Simplify sdk/python/examples/background_agent.py: create the workspace with git=mitos.git(paths=["/workspace/repo"]), remove the hand-rolled CRD patch and its honest-gap note, and add an import-time spec-surface check.
  • Document the helper in sdk/python/README.md under a new "Durable workspaces and spec.git" subsection.
  • Add sdk/python/tests/test_git.py (12 tests) covering construction, defaults, credentials rendering, validation errors, create_workspace plumbing, set_git, and the package export.

Verification

  • cd sdk/python && PYTHONPATH=. python3 -m pytest tests/ : 352 passed, 1 skipped.
  • PYTHONPATH=. python3 -m pytest tests/test_git.py -v : 12 passed.
  • sdk-examples gate reproduced locally: python3 -m py_compile sdk/python/examples/*.py and the import-check (module-level exec) pass for every example; every README python fence byte-compiles (24 fences, 0 failures).
  • No em or en dashes in any added line (checked with a Unicode grep over all changed files).

Risks

Low risk. The change is additive and pure spec construction: no server, cluster, or KVM path is touched. create_workspace keeps its prior behavior when git is not passed (the spec.git key is omitted). The push-credentials token is never accepted or emitted; only a Secret name and key reference is recorded.

Model Used

Claude Opus 4.8 (1M context), model id claude-opus-4-8[1m], extended thinking mode.

Checklist

  • PR title is a conventional commit (feat, fix, docs, ci, chore, refactor, test)
  • Thinking Path traces from project context to this change
  • Model Used is filled in (with version and capability details)
  • Tests added for behavior changes, in the same commit (TDD)
  • Docs updated in the same PR
  • Threat-model delta (docs/threat-model.md) included if the security surface moved
  • Benchmark run (bench/) included if the hot path was touched
  • No em or en dashes introduced anywhere
  • Secret values never logged, in errors, in condition messages, or on host paths
  • No internal/instance-local references (only public #NNN / mitos-run/mitos URLs)
  • Every commit carries a Signed-off-by trailer (git commit -s)

Summary by CodeRabbit

  • New Features
    • Added first-class Python helpers (mitos.git / GitSpec) to declaratively set spec.git.paths and optional credential references.
    • Workspaces can now be created with Git settings directly, and updated via Workspace.set_git(...).
    • Re-exported git and GitSpec as part of the public Python API.
  • Documentation
    • Expanded the Python README with “Durable workspaces and spec.git” examples, including secret-based rendezvous authentication.
  • Bug Fixes
    • Improved fail-fast validation with specific error codes, and ensured credential fields are cleared when omitted.

Add mitos.git(...) so a caller declares a Workspace spec.git (the mitos.run/v1
WorkspaceGit) declaratively: the repo paths that get version history and the
fork-and-merge rendezvous remote, plus an optional push-credentials reference,
instead of hand-patching the Workspace CRD.

The helper is pure spec construction (no server, no cluster, no KVM). It is
plumbed into AgentRun.create_workspace(name, git=...) and Workspace.set_git(...),
accepting a GitSpec or a bare list of paths. Validation fails fast with
LLM-legible errors (invalid_git_paths, invalid_git_credentials). The push token
is a secret value: the helper only ever records a Secret name and key, never the
token itself.

Simplify the background_agent example to declare spec.git.paths through the
helper at create time, removing the raw patch_namespaced_custom_object
workaround, and document the helper in the SDK README.

Closes #619

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jannes Stubbemann <jannes@openclaw.rocks>
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6d3e1899-9c74-4415-8954-79c4315336e0

📥 Commits

Reviewing files that changed from the base of the PR and between cff26b9 and d00189b.

📒 Files selected for processing (1)
  • sdk/python/mitos/__init__.py

📝 Walkthrough

Walkthrough

Adds a first-class mitos.git helper for declaring spec.git.paths and optional credentials, integrates it with workspace creation and patching, exports it from the package, updates the example and README, and adds tests.

Changes

spec.git helper feature

Layer / File(s) Summary
GitSpec dataclass and validation helpers
sdk/python/mitos/git.py
Defines GitSpec, git(), and coerce_git() with spec serialization, normalization, and validation.
Workspace git wiring and exports
sdk/python/mitos/client.py, sdk/python/mitos/workspace.py, sdk/python/mitos/__init__.py, sdk/python/README.md
AgentRun.create_workspace accepts git specifications, Workspace.set_git() patches spec.git, the new symbols are re-exported, and usage is documented.
background_agent example uses mitos.git
sdk/python/examples/background_agent.py
The example declares git paths during workspace creation and updates its API checks and documentation.
Test suite for git helper
sdk/python/tests/test_git.py
Tests construction, serialization, validation, workspace integration, credential clearing, and package exports.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant AgentRun
  participant coerce_git
  participant KubernetesAPI
  participant Workspace
  Caller->>AgentRun: create_workspace(name, git)
  AgentRun->>coerce_git: normalize git input
  coerce_git-->>AgentRun: return GitSpec
  AgentRun->>KubernetesAPI: create Workspace with spec.git
  Caller->>Workspace: set_git(git)
  Workspace->>coerce_git: normalize git input
  coerce_git-->>Workspace: return GitSpec
  Workspace->>KubernetesAPI: patch spec.git
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is conventional, concise, and accurately summarizes the new first-class spec.git helper for durable workspaces.
Description check ✅ Passed The description includes the required Thinking Path, linked issue, What Changed, Verification, Risks, Model Used, and Checklist sections.
Linked Issues check ✅ Passed The PR adds the first-class git helper, wires it into workspace creation, and updates the example, matching the main goal of #619.
Out of Scope Changes check ✅ Passed The README, tests, API exports, example, and workspace/client changes all support the git helper feature and are in scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/python-spec-git-619

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@sdk/python/mitos/git.py`:
- Around line 37-130: Validation currently lives only in git(), so direct
GitSpec(...) construction can bypass the fail-fast checks and let invalid data
reach coerce_git() and to_spec(). Move the existing paths/credentials validation
logic into GitSpec.__post_init__ so every construction path is enforced,
including exported mitos.GitSpec usage, and keep git() as a thin wrapper that
just builds GitSpec. Make sure __post_init__ covers the same rules for paths,
credentials_secret, and credentials_username-without-secret.

In `@sdk/python/mitos/workspace.py`:
- Around line 246-262: The set_git method in Workspace currently patches
spec.git with merge-patch semantics, so unset credential fields are preserved
instead of cleared. Update set_git() to include credentialsSecretRef and
credentialsUsername as explicit null values whenever coerce_git(git).to_spec()
does not set them, so patch_namespaced_custom_object removes any previously
stored credentials. Use the existing Workspace.set_git and coerce_git helpers to
locate and adjust the patch payload.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 23cb622b-119d-4d05-ad06-614f12cc70c5

📥 Commits

Reviewing files that changed from the base of the PR and between f74f4f0 and 73a438a.

📒 Files selected for processing (7)
  • sdk/python/README.md
  • sdk/python/examples/background_agent.py
  • sdk/python/mitos/__init__.py
  • sdk/python/mitos/client.py
  • sdk/python/mitos/git.py
  • sdk/python/mitos/workspace.py
  • sdk/python/tests/test_git.py

Comment thread sdk/python/mitos/git.py
Comment thread sdk/python/mitos/workspace.py
…stale creds

Address CodeRabbit review on the spec.git helper:

- Move validation into GitSpec.__post_init__ (shared _validate_git_args) so a
  directly constructed mitos.GitSpec is validated too, not only the git()
  factory; git() is now a thin wrapper.
- In Workspace.set_git, send credentialsSecretRef and credentialsUsername as
  explicit null when unset, so a merge-patch that drops credentials actually
  clears the previously stored reference instead of preserving it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jannes Stubbemann <jannes@openclaw.rocks>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
sdk/python/tests/test_git.py (1)

55-80: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider parametrizing validation tests.

Per the description, this segment covers multiple invalid-input cases (empty paths, malformed credential tuples) as separate test functions. Consolidating with pytest.mark.parametrize would reduce duplication as more invalid-input cases are added later.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sdk/python/tests/test_git.py` around lines 55 - 80, The validation tests in
test_git.py are duplicated across multiple near-identical cases, so consolidate
them into a parametrized pytest test to make adding future invalid-input cases
easier. Update the existing test functions around mitos.git to use
pytest.mark.parametrize for the invalid paths and malformed credentials
scenarios, while preserving the current AgentRunError assertions and expected
error codes/remediation checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@sdk/python/tests/test_git.py`:
- Around line 55-80: The validation tests in test_git.py are duplicated across
multiple near-identical cases, so consolidate them into a parametrized pytest
test to make adding future invalid-input cases easier. Update the existing test
functions around mitos.git to use pytest.mark.parametrize for the invalid paths
and malformed credentials scenarios, while preserving the current AgentRunError
assertions and expected error codes/remediation checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6ec4b3bd-dacb-4ea9-8768-7deb0a58a48a

📥 Commits

Reviewing files that changed from the base of the PR and between 73a438a and d928343.

📒 Files selected for processing (3)
  • sdk/python/mitos/git.py
  • sdk/python/mitos/workspace.py
  • sdk/python/tests/test_git.py

…id_git_credentials error

A realistic misuse of a credentials-named argument is passing the raw
token itself; the repr in the error cause would put that token verbatim
into an exception message. Report the received type instead of the
value, and pin the hygiene with a test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Jannes Stubbemann <jannes@openclaw.rocks>
@stubbi stubbi enabled auto-merge (squash) July 9, 2026 21:09
@stubbi stubbi merged commit 045dd0b into main Jul 10, 2026
35 checks passed
@stubbi stubbi deleted the feat/python-spec-git-619 branch July 10, 2026 23:47
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.

Python SDK: first-class spec.git helper for cloning a repo into a sandbox

1 participant