Skip to main content

repo.fetch

The "clone a git repo into the session" pack. Caller supplies a git url; the pack writes vault-resolved credentials to a temp file inside the session, runs git clone with the appropriate transport config (SSH key via GIT_SSH_COMMAND, HTTPS PAT via GIT_ASKPASS), and shreds the credential before returning. The agent never sees the secret.

What sets repo.fetch apart from a plain git clone shell call is the context envelope in the response: tree (up to 300 paths), README content, recognized entrypoints (Makefile, go.mod, package.json, CLAUDE.md, etc.), doc-discovery hints, and a signals block (has_readme, has_docs_dir, has_code, sparse, doc_file_count, code_file_count). One tool call returns enough orientation that the agent doesn't need a follow-up fs.list to figure out what's in the repo.

Inputs

FieldTypeRequiredDefaultNotes
urlstringyesGit URL. Three forms accepted: git@github.com:owner/repo.git (scp-like SSH), ssh://git@github.com/owner/repo.git (URL SSH), https://github.com/owner/repo.git (HTTPS, public or with vault credential).
refstringnoHEADBranch or tag to check out after cloning.
depthnumbernofull clonePass 1 for a shallow clone (faster, smaller).
credentialstringnoVault credential name. Required for private HTTPS repos; for SSH the pack resolves a key by host match (no name needed).

Outputs

FieldTypeNotes
urlstringEcho of the input.
refstringResolved ref.
commitstringHEAD SHA after the clone (and post-checkout if ref was set).
clone_pathstring/tmp/helmdeck-clone-<rand>. Pass this back as clone_path to every follow-up fs.* / cmd.run / git.* / repo.push call, plus propagate _session_id (see Session chaining).
credentialstringVault record name actually used (or "" for public clones).
filesnumberTotal git ls-files count.
treearrayUp to 300 relative paths. Sorted.
tree_totalnumberTrue count even if tree was truncated.
tree_truncatedbooleantrue when files > 300 — narrow follow-ups with fs.list + a glob from doc_hints.
readmeobject{path, content (≤4096 bytes), truncated} for the auto-detected top-level README. null when no README exists.
entrypointsarray[{path, kind}]kind is one of build, go, node, python, rust, java, gradle, devfile, container, compose, agent-doc, contributing.
doc_hintsarrayGlob suggestions for fs.list (docs/**/*.md, content/**/*.adoc, etc.). Static — no per-repo computation.
signalsobjectCoarse classifier the agent branches on: {has_readme, has_docs_dir, has_code, doc_file_count, code_file_count, sparse}. See SKILLS.md §"Repo discovery pattern" for the decision table.

Vault credentials needed

Optional — public HTTPS clones work without a credential.

For private repos:

  • SSH — type ssh-git, host pattern matches the git host (e.g. github.com). Resolved by the pack via host-match; no credential argument needed.
  • HTTPS PAT — type api_key, host pattern api.github.com (or your provider's API host). Pass credential: "<vault-name>" in the input.

The PAT/key is written to a 0600 temp file inside the session, used via GIT_ASKPASS / GIT_SSH_COMMAND, and shred'd on exit. The agent never sees the secret value.

Use it from your agent (OpenClaw chat-UI worked example)

Prompt (sent in OpenClaw chat UI / openclaw-cli agent):

Use helmdeck__repo-fetch to clone https://github.com/tosin2013/helmdeck.git. Tell me the commit SHA, total file count, whether the readme was found, and which entrypoints (Makefile, go.mod, CLAUDE.md, etc.) the response surfaced.

Tool call (1 call, no failures):

{
"name": "helmdeck__repo-fetch",
"arguments": {
"url": "https://github.com/tosin2013/helmdeck.git"
}
}

Pack response (truncated):

{"pack":"repo.fetch","version":"v1","output":{"clone_path":"/tmp/helmdeck-clone-66wkAG","commit":"0eb718893a0a49431c34292d23fee7412e4a828b","credential":"","doc_hints":["README*","docs/**/*.md","docs/**/*.adoc","docs/**/*.rst","content/**/*.md","content/**/*.adoc"],"entrypoints":[{"kind":"build","path":"Makefile"},{"kind":"go","path":"go.mod"},{"kind":"agent-doc","path":"CLAUDE.md"},{"kind":"contributing","path":"CONTRIBUTING.md"}],"files":407,"readme":{"content":"# helmdeck\n\n\u003e Today's helmdeck install ran a full 6-step code-edit loop (clone, read, patch,\n\u003e test, commit, push) on `gpt-oss-120b` for **$0.07**. The same loop on Cursor\n\u003e or Claude Code direct via Sonnet would have cost **$0.30+**. Same outcome,\n\u003e ~5× cheaper — and the \"expensive\" stack isn't even th
...[truncated]

Agent's final reply:

Repo clone details for https://github.com/tosin2013/helmdeck.git

  • Commit SHA: 0eb718893a0a49431c34292d23fee7412e4a828b
  • Total file count: 407 files in the repository (tree total).
  • README found: Yes – README.md was present (truncated excerpt included in the response).
  • Entry‑point files surfaced by the pack:
    • Makefile (kind: build)
    • go.mod (kind: go)
    • CLAUDE.md (kind: agent‑doc)
    • CONTRIBUTING.md (kind: contributing)

These are the primary entry points the helmdeck__repo-fetch pack identified.

Verified via OpenClaw 2026.5.6 + helmdeck v0.9.0-dev + openrouter/openai/gpt-oss-120b on 2026-05-07 (cost: $0.0015).

Developer reference (curl)

ADMIN_PW=$(grep HELMDECK_ADMIN_PASSWORD /root/helmdeck/deploy/compose/.env.local | cut -d= -f2)
JWT=$(curl -fsS -X POST http://localhost:3000/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d "{\"username\":\"admin\",\"password\":\"${ADMIN_PW}\"}" \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["token"])')

# Public HTTPS clone:
curl -fsS -X POST http://localhost:3000/api/v1/packs/repo.fetch \
-H "Authorization: Bearer $JWT" -H 'Content-Type: application/json' \
-d '{"url":"https://github.com/tosin2013/helmdeck.git"}'

# Private clone with vault PAT:
curl -fsS -X POST http://localhost:3000/api/v1/packs/repo.fetch \
-H "Authorization: Bearer $JWT" -H 'Content-Type: application/json' \
-d '{"url":"https://github.com/your-org/private.git","credential":"github-token"}'

Captured response shape (truncated):

{
"pack": "repo.fetch",
"version": "v1",
"output": {
"clone_path": "/tmp/helmdeck-clone-Xxxxx",
"commit": "abc1234567...",
"credential": "",
"files": 385,
"tree": ["CLAUDE.md", "CONTRIBUTING.md", "Makefile", "..."],
"tree_total": 385,
"tree_truncated": true,
"readme": {"path": "README.md", "content": "# helmdeck\n...", "truncated": false},
"entrypoints": [
{"kind": "build", "path": "Makefile"},
{"kind": "go", "path": "go.mod"},
{"kind": "agent-doc", "path": "CLAUDE.md"},
{"kind": "contributing","path": "CONTRIBUTING.md"}
],
"doc_hints": ["README*", "docs/**/*.md", "docs/**/*.adoc"],
"signals": {"has_readme": true, "has_docs_dir": true, "has_code": true, "sparse": false}
},
"session_id": "..."
}

Error codes

CodeTriggersCaptured response
invalid_inputurl missing{"error":"invalid_input","message":"url is required"}
invalid_inputURL host resolves to a blocked range (metadata, RFC 1918, loopback){"error":"invalid_input","message":"egress denied: …"}
invalid_inputRemote has no branches (newly-created empty repo){"error":"invalid_input","message":"remote https://… has no branches; push at least one commit before cloning"} (fast-fail per issue #94)
invalid_inputcredential set but vault has no matching record{"error":"invalid_input","message":"vault credential \"name\" not found"}
handler_failedgit clone exit non-zero (network, auth, missing repo)git clone exit N: … (stderr truncated to 1024 chars)
session_unavailableEngine has no session executorengine has no session executor

Session chaining

Required (creates the session). repo.fetch is the canonical session-creating pack — every follow-on fs.read, fs.write, fs.list, fs.patch, fs.delete, cmd.run, git.commit, git.diff, git.log, repo.push, repo.map, content.ground (in file mode) needs both _session_id AND clone_path from this response. See SKILLS.md §"Session chaining contract" for what happens when you forget.

PreserveSession: true — the session persists 5 minutes after the last call (watchdog cleanup) so chained workflows reuse the same Chromium / sidecar instance. Subsequent calls within that window are warm (~1–3s); first call is cold (~10–30s for sidecar boot + clone).

Async behavior

Synchronous. Wall-clock = sidecar boot (~5–15s on cold session) + git clone over the network + envelope computation (~1s for a 300-file tree). Heavy repos (Linux kernel, large monorepos) can hit the 5-minute session-creation timeout — pass depth: 1 to bound the work.

See also