Sign inSign up

olegselajev241/herdr-crew-kit:0.5.1

Manifest digest

sha256:854a453ca9a9f181fea979ce8d5fab8b5ba913ac592aba8fa98e79a7f2c9dc75

Last pushed

19 days by olegselajev241

Type

Sandbox Kit

Manifest digest

sha256:854a453ca9a9f181fea979ce8d5fab8b5ba913ac592aba8fa98e79a7f2c9dc75

yaml
schemaVersion: "2"
kind: sandbox
name: herdr-crew
version: 0.5.1
displayName: Herdr Crew
description: |
    Task sandbox running a nested Herdr server and a crew of coding agents
    (Claude Code, Codex, pi with Google models) in rotating roles: a sandboxed orchestrator
    that holds the goal, plus planner, implementer, and QC. The host only
    delivers goals and arbitrates resources.
sourceURL: https://github.com/shelajev/herdr
args:
    claude_model:
        default: claude-opus-5-5
        description: Model passed explicitly to Claude Code
    codex_model:
        default: gpt-6.1-sol
        description: Model passed explicitly to Codex
    gemini_model:
        default: gemini-3.8-flash
        description: Google model the pi role pins with --provider google --model
    image:
        default: docker.io/olegselajev241/herdr-crew:0.5.1
        description: Herdr crew template image. The 0.5.1 default is published for linux/arm64 (digest sha256:45787cc3a320ee7677a1ca248beff29093d78748a30bbf6b7f7a4bae9eca230f), but this kit version is still an unpublished candidate, and promotion waits for real sandbox acceptance; for local builds pass herdr-crew:local after scripts/sbx/build-crew-template.sh
    pi_provider:
        default: google
        description: Provider paired with the pi model
    roles:
        default: orchestrator=claude,planner=codex,implementer=claude,qc=pi
        description: Role assignment for this task; the host rotates this per task and guarantees qc differs from implementer
sandbox:
    image: ${{ kit.args.image }}
    entrypoint:
        - crew-entry
agentInstructions:
    filename: AGENTS.md
    content: |
        ## Herdr crew

        This sandbox runs a crew of coding agents: an orchestrator that holds the
        task goal and coordinates everyone through the local herdr CLI, plus a
        planner, an implementer, and quality control. Your role is named in the
        prompt you receive; read your prompt pack in `/home/agent/crew/roles/`
        and follow it. Only the orchestrator drives other agents; every other
        role works solely on what it is prompted with. The role-to-agent
        assignment for this task is recorded in `/home/agent/crew/assignment`.

        Shared crew files under `/home/agent/crew/`: `goal.md` (the goal, owned by
        the orchestrator), `plan.md` (the plan, owned by the planner), `qc-log.md`
        (findings and VERDICT lines, owned by qc), `status.md` (progress notes and
        the final RESULT line, owned by the orchestrator), and `escalations.md`
        (resource requests for the host to approve or deny).
permissions:
    network:
        allow:
            - api.anthropic.com
            - statsig.anthropic.com
            - claude.ai
            - console.anthropic.com
            - platform.claude.com
            - downloads.claude.ai
            - claude.com
            - code.claude.com
            - api.openai.com
            - openai.com
            - auth.openai.com
            - chatgpt.com
            - files.openai.com
            - codeload.github.com
            - generativelanguage.googleapis.com
            - herdr.dev
            - github.com
            - api.github.com
            - raw.githubusercontent.com
            - objects.githubusercontent.com
            - release-assets.githubusercontent.com
            - registry.npmjs.org
            - archive.ubuntu.com
            - security.ubuntu.com
            - ports.ubuntu.com
            - download.docker.com
credentials:
    - service: anthropic
      apiKey:
        name: ANTHROPIC_API_KEY
        inject:
            - domain: api.anthropic.com
              header: x-api-key
              format: '%s'
            - domain: claude.ai
              header: x-api-key
              format: '%s'
            - domain: console.anthropic.com
              header: x-api-key
              format: '%s'
      oauth:
        tokenEndpoint:
            host: platform.claude.com
            path: /v1/oauth/token
        sentinels:
            accessToken: sk-ant-oat01-proxy-managed
            refreshToken: sk-ant-ort01-proxy-managed
        credentialFile:
            path: ~/.claude/.credentials.json
            template: '{"claudeAiOauth":{"accessToken":"{{.AccessToken}}","refreshToken":"{{.RefreshToken}}","expiresAt":{{.ExpiresAt}},"scopes":{{.ScopesJSON}}}{{if .PrimaryApiKey}},"primaryApiKey":"{{.PrimaryApiKey}}"{{end}}}'
        skipIfEnv:
            - ANTHROPIC_API_KEY
    - service: openai
      apiKey:
        name: OPENAI_API_KEY
        inject:
            - domain: api.openai.com
              header: Authorization
              format: Bearer %s
            - domain: openai.com
              header: Authorization
              format: Bearer %s
      oauth:
        tokenEndpoint:
            host: auth.openai.com
            path: /oauth/token
        resourceHosts:
            - chatgpt.com
        sentinels:
            accessToken: oai-oat01-proxy-managed
            refreshToken: oai-ort01-proxy-managed
        skipIfEnv:
            - OPENAI_API_KEY
    - service: gemini
      required: true
      apiKey:
        name: GEMINI_API_KEY
        proxyManaged: true
        inject:
            - domain: generativelanguage.googleapis.com
              header: x-goog-api-key
              format: '%s'
environment:
    variables:
        CODEX_HOME: /home/agent/.codex
        GIT_TERMINAL_PROMPT: "0"
        HERDR_CREW: "1"
        HERDR_CREW_CLAUDE_MODEL: ${{ kit.args.claude_model }}
        HERDR_CREW_CODEX_MODEL: ${{ kit.args.codex_model }}
        HERDR_CREW_GEMINI_MODEL: ${{ kit.args.gemini_model }}
        HERDR_CREW_PI_PROVIDER: ${{ kit.args.pi_provider }}
        IS_SANDBOX: "1"
setup:
    install:
        - command: command -v python3 >/dev/null
          user: "1000"
          description: Verify Python is available for crew model and phase helpers
        - command: crew-check
          user: "1000"
          description: Verify herdr and the crew agent CLIs are present
        - command: |
            set -e
            ws="${WORKSPACE_DIR:-/}"
            esc=$(printf '%s' "$ws" | sed 's/\\/\\\\/g; s/"/\\"/g; s/\t/\\t/g; s/\r/\\r/g')
            projects="\"/\": { \"hasTrustDialogAccepted\": true }"
            [ "$ws" = "/" ] || projects="$projects, \"$esc\": { \"hasTrustDialogAccepted\": true }"
            printf '%s\n' "{
              \"bypassPermissionsModeAccepted\": true,
              \"hasCompletedOnboarding\": true,
              \"projects\": { $projects }
            }" > /home/agent/.claude.json
            chown agent:agent /home/agent/.claude.json
          user: "0"
          description: Seed Claude bypass/trust flags
        - command: |
            set -e
            mkdir -p /home/agent/.claude
            HELPER=''
            if [ "${SBX_CRED_ANTHROPIC_MODE:-none}" != none ]; then
              HELPER='  "apiKeyHelper": "echo proxy-managed",
            '
            fi
            printf '%s' "{
              \"themeId\": 1,
              \"alwaysThinkingEnabled\": true,
            ${HELPER}  \"permissions\": { \"defaultMode\": \"bypassPermissions\" },
              \"bypassPermissionsModeAccepted\": true,
              \"skipDangerousModePermissionPrompt\": true
            }
            " > /home/agent/.claude/settings.json
          user: agent
          description: Seed Claude settings.json from SBX_CRED_ANTHROPIC_MODE
        - command: |
            set -e
            mkdir -p /home/agent/.codex
            MODE="${SBX_CRED_OPENAI_MODE:-none}"
            cat > /home/agent/.codex/config.toml << 'EOF'
            approval_policy = "never"
            sandbox_mode = "danger-full-access"
            mcp_oauth_credentials_store = "file"
            check_for_update_on_startup = false
            EOF
            case "$MODE" in
              oauth|apikey)
                cat >> /home/agent/.codex/config.toml << 'EOF'
            forced_login_method = "api"
            EOF
                ;;
            esac
            if [ "$MODE" = oauth ]; then
              cat >> /home/agent/.codex/config.toml << 'EOF'
            model_provider = "sandboxd"
            [model_providers.sandboxd]
            name = "Sandbox Proxy"
            base_url = "https://chatgpt.com/backend-api/codex"
            experimental_bearer_token = "oai-oat01-proxy-managed"
            requires_openai_auth = false
            EOF
            fi
            case "$MODE" in
              oauth|apikey)
                cat > /home/agent/.codex/auth.json << 'EOF'
            {
              "OPENAI_API_KEY": "proxy-managed"
            }
            EOF
                ;;
              *)
                rm -f /home/agent/.codex/auth.json
                ;;
            esac
          user: agent
          description: Seed Codex config/auth from SBX_CRED_OPENAI_MODE
        - command: |
            set -e
            fail() {
              printf 'herdr-crew: %s; cannot seed Codex trust for the task workspace; the host pair smoke must confirm which variable carries the runtime workspace path during install\n' "$*" >&2
              exit 1
            }
            nl=$(printf '\nx')
            nl=${nl%x}
            raw="${WORKSPACE_DIR:-}"
            [ -n "$raw" ] || fail "WORKSPACE_DIR is unset or empty"
            case "$raw" in
              *[[:cntrl:]]*) fail "WORKSPACE_DIR contains control characters" ;;
              /*) ;;
              *) fail "WORKSPACE_DIR is not an absolute path ('$raw')" ;;
            esac
            # The sentinel keeps command substitution from stripping a trailing
            # newline that belongs to the resolved name; that newline is then seen
            # by the control-character check instead of silently naming another
            # directory.
            ws=$(readlink -f -- "$raw" 2>/dev/null || :; printf x)
            ws=${ws%x}
            ws=${ws%"$nl"}
            [ -n "$ws" ] || fail "WORKSPACE_DIR ('$raw') cannot be resolved (readlink -f failed or is missing)"
            case "$ws" in
              /) fail "WORKSPACE_DIR ('$raw') resolves to the filesystem root" ;;
              *[[:cntrl:]]*) fail "WORKSPACE_DIR ('$raw') resolves to a path with control characters" ;;
            esac
            [ -d "$ws" ] || fail "WORKSPACE_DIR ('$raw') is not a directory"
            # The trusted path must be the very directory that was validated.
            [ "$ws" -ef "$raw" ] || fail "WORKSPACE_DIR ('$raw') does not resolve to the same directory as its canonical path"
            home=$(readlink -f -- "${HOME:-/home/agent}" 2>/dev/null) || home=""
            for h in /home/agent "$home"; do
              [ -n "$h" ] || continue
              case "$h/" in
                "$ws"/*) fail "WORKSPACE_DIR ('$raw') is the agent home directory or an ancestor of it" ;;
              esac
            done
            case "$ws" in
              /home | /tmp | /usr | /etc | /var | /root) fail "WORKSPACE_DIR ('$raw') is a system directory" ;;
            esac
            printf '%s\n' "herdr-crew: seeding Codex trust for $ws (from WORKSPACE_DIR)"
            esc=$(printf '%s' "$ws" | sed 's/\\/\\\\/g; s/"/\\"/g')
            header="[projects.\"$esc\"]"
            if ! grep -qxF "$header" /home/agent/.codex/config.toml; then
              printf '%s\ntrust_level = "trusted"\n' "$header" >> /home/agent/.codex/config.toml
            fi
          user: agent
          description: Seed Codex trust for the task workspace only
    startup:
        - command:
            - sh
            - -c
            - export PATH="/home/agent/.local/bin:$PATH"; while true; do herdr agent list >/dev/null 2>&1 || herdr server >>/tmp/herdr-server.log 2>&1; sleep 5; done
          user: agent
          background: true
          description: Keep the headless herdr server running in detached sandboxes
    files:
        - path: /home/agent/crew/models
          content: claude=${{ kit.args.claude_model }},codex=${{ kit.args.codex_model }},pi=${{ kit.args.pi_provider }}/${{ kit.args.gemini_model }}
          description: Authoritative model pins for all crew start paths
        - path: /home/agent/crew/assignment
          content: ${{ kit.args.roles }}
          description: Role-to-agent assignment for this task
        - path: /home/agent/crew/workdir
          content: ${WORKDIR}
          description: Absolute workspace path, read by the host task driver