-
Notifications
You must be signed in to change notification settings - Fork 103
Add fullsend run agent command and experiment for test it #231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
14 changes: 14 additions & 0 deletions
14
experiments/runner-hello-world/.fullsend/agents/hello-world.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| --- | ||
| name: hello-world | ||
| description: A minimal agent that runs a tool and summarizes the repository code. | ||
| skills: | ||
| - hello-world-summary | ||
| tools: Bash(hello-world-bin) | ||
| model: sonnet | ||
| --- | ||
|
|
||
| You are a minimal test agent. Your job is to: | ||
|
|
||
| 1. Run the `hello-world-bin` tool — this writes `output/hello-world.md` | ||
| 2. Explore the repository in the current path | ||
| 3. Use the `hello-world-summary` skill to write a summary of the repository to `output/summary.md` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| export CLAUDE_CODE_USE_VERTEX=1 | ||
| export ANTHROPIC_VERTEX_PROJECT_ID=${ANTHROPIC_VERTEX_PROJECT_ID} | ||
| export CLOUD_ML_REGION=${CLOUD_ML_REGION} | ||
| export GOOGLE_APPLICATION_CREDENTIALS=/tmp/workspace/.gcp-credentials.json |
24 changes: 24 additions & 0 deletions
24
experiments/runner-hello-world/.fullsend/harness/hello-world.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # harness/hello-world.yaml | ||
| agent: agents/hello-world.md | ||
| model: sonnet | ||
| image: quay.io/manonru/fullsend-exp:latest | ||
| policy: policies/hello-world.yaml | ||
|
|
||
| host_files: | ||
| - src: env/gcp-vertex.env | ||
| dest: /tmp/workspace/.env.d/gcp-vertex.env | ||
| expand: true | ||
| - src: ${GOOGLE_APPLICATION_CREDENTIALS} | ||
| dest: /tmp/workspace/.gcp-credentials.json | ||
|
|
||
| skills: | ||
| - skills/hello-world-summary | ||
|
|
||
| validation_loop: | ||
| script: scripts/validate-output.sh | ||
| max_iterations: 3 | ||
|
|
||
| runner_env: | ||
| VALIDATION_EXPECTED_FAILURES: "1" | ||
|
|
||
| timeout_minutes: 5 |
28 changes: 28 additions & 0 deletions
28
experiments/runner-hello-world/.fullsend/policies/hello-world.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| version: 1 | ||
|
|
||
| # Minimal policy for the hello-world agent. | ||
| # Only allows outbound access to Google Cloud APIs (Vertex AI authentication). | ||
|
|
||
| filesystem_policy: | ||
| include_workdir: true | ||
| read_only: [/usr, /lib, /proc, /dev/urandom, /app, /etc, /var/log] | ||
| read_write: [/sandbox, /tmp, /dev/null] | ||
| landlock: | ||
| compatibility: best_effort | ||
| process: | ||
| run_as_user: sandbox | ||
| run_as_group: sandbox | ||
|
|
||
| network_policies: | ||
| vertex_ai: | ||
| name: vertex-ai | ||
| endpoints: | ||
| - host: "*.googleapis.com" | ||
| port: 443 | ||
| protocol: tcp | ||
| enforcement: enforce | ||
| access: allow | ||
| binaries: | ||
| - path: "**/curl" | ||
| - path: "**/claude" | ||
| - path: "**/node" |
45 changes: 45 additions & 0 deletions
45
experiments/runner-hello-world/.fullsend/scripts/validate-output.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| HELLO_FILE="output/hello-world.md" | ||
| SUMMARY_FILE="output/summary.md" | ||
|
|
||
| # Counter-based failure for testing retry logic. | ||
| # VALIDATION_EXPECTED_FAILURES controls how many times to fail before passing. | ||
| # Counter file lives in FULLSEND_RUN_DIR so it persists across iterations. | ||
| EXPECTED_FAILURES="${VALIDATION_EXPECTED_FAILURES:-0}" | ||
| COUNTER_FILE="${FULLSEND_RUN_DIR:-.}/.validation-counter" | ||
|
|
||
| if [ "$EXPECTED_FAILURES" -gt 0 ]; then | ||
| COUNT=0 | ||
| if [ -f "$COUNTER_FILE" ]; then | ||
| COUNT=$(cat "$COUNTER_FILE") | ||
| fi | ||
| COUNT=$((COUNT + 1)) | ||
| echo "$COUNT" > "$COUNTER_FILE" | ||
|
|
||
| if [ "$COUNT" -le "$EXPECTED_FAILURES" ]; then | ||
| echo "FAIL: deliberate failure $COUNT of $EXPECTED_FAILURES (testing retry)" | ||
| exit 1 | ||
| fi | ||
| fi | ||
|
|
||
| # Validate hello-world.md exists and contains expected output. | ||
| if [ ! -f "$HELLO_FILE" ]; then | ||
| echo "FAIL: $HELLO_FILE not found" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if ! grep -q "Hello world from repo" "$HELLO_FILE"; then | ||
| echo "FAIL: $HELLO_FILE missing expected 'Hello world from repo' line" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Validate summary.md exists. | ||
| if [ ! -f "$SUMMARY_FILE" ]; then | ||
| echo "FAIL: $SUMMARY_FILE not found" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "PASS: output validated" | ||
| exit 0 | ||
15 changes: 15 additions & 0 deletions
15
experiments/runner-hello-world/.fullsend/skills/hello-world-summary/SKILL.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| --- | ||
| name: hello-world-summary | ||
| description: Explore the repository and produce a summary of its code | ||
| allowed-tools: Read, Glob, Grep | ||
| --- | ||
|
|
||
| Explore the repository in the current directory and produce a summary. | ||
|
|
||
| The summary should include: | ||
| - The repository name | ||
| - A brief description of what the repository contains | ||
| - The main languages and frameworks used | ||
| - A list of the top-level directories and their purpose | ||
|
|
||
| Write the summary to `$FULLSEND_OUTPUT_DIR/summary.md` (the `FULLSEND_OUTPUT_DIR` environment variable points to the output directory). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| # How to run the experiment | ||
|
|
||
| ## Two-repo model | ||
|
|
||
| This experiment uses a two-repo setup that mirrors the production layout: | ||
|
|
||
| - **`.fullsend` repo** (`test-fullsend/.fullsend`): Contains the harness definition, agents, skills, env files, policies, scripts, and the GitHub Actions workflow. This is where the workflow runs. | ||
| - **Target repo** (`test-fullsend/test-repo`): The codebase the agent analyzes. Checked out by the workflow and passed to the CLI via `--target-repo`. | ||
|
|
||
| The `run-experiment.sh` script syncs the `.fullsend/` directory and workflow to the `.fullsend` repo, then triggers the workflow with the target repo as an input. | ||
|
|
||
| ## Requirements | ||
|
|
||
| ### Local (to run the experiment) | ||
|
|
||
| - **Go toolchain** (1.23+) | ||
| - **gh CLI** authenticated with access to the fullsend fork and both repos in the target org | ||
| - **podman** (for building and pushing the container image) | ||
| - **rsync** | ||
| - A local clone of the `.fullsend` repo (see below) | ||
|
|
||
| ### Repos | ||
|
|
||
| The default setup uses the `test-fullsend` org with two repos: | ||
|
|
||
| - `test-fullsend/.fullsend` — harness and workflow (secrets configured here) | ||
| - `test-fullsend/test-repo` — target codebase for the agent | ||
|
|
||
| The `.fullsend` repo needs **GitHub secrets** configured (see [Setting up GCP secrets](#setting-up-gcp-secrets) below) and a **GitHub release** on your fullsend fork (used to distribute the binary to the runner). | ||
|
|
||
| ### Setting up GCP secrets | ||
|
|
||
| The experiment uses Claude Code via Vertex AI, which requires a GCP project with the Vertex AI API enabled and a service account key. | ||
|
|
||
| **If you already use Claude Code via Vertex AI locally** (i.e. `ANTHROPIC_VERTEX_PROJECT_ID` and `CLOUD_ML_REGION` are set in your environment), you already have a GCP project with the Vertex AI API enabled — skip step 1 and reuse your project ID and region for the secrets in step 4: | ||
|
|
||
| ```bash | ||
| gh secret set GCP_PROJECT --repo your-org/.fullsend --body "${ANTHROPIC_VERTEX_PROJECT_ID}" | ||
| gh secret set GCP_REGION --repo your-org/.fullsend --body "${CLOUD_ML_REGION}" | ||
| ``` | ||
|
|
||
| You still need a service account key for CI (steps 2-4), since the workflow can't use interactive authentication like `gcloud auth application-default login`. | ||
|
|
||
| **If you need to set up Vertex AI from scratch**, follow all steps below: | ||
|
|
||
| 1. **Create or select a GCP project** with the [Vertex AI API](https://console.cloud.google.com/apis/library/aiplatform.googleapis.com) enabled. | ||
|
|
||
| 2. **Create a service account** with the `Vertex AI User` role: | ||
| ```bash | ||
| gcloud iam service-accounts create fullsend-runner \ | ||
| --display-name="Fullsend Runner" \ | ||
| --project=${ANTHROPIC_VERTEX_PROJECT_ID} | ||
|
|
||
| gcloud projects add-iam-policy-binding ${ANTHROPIC_VERTEX_PROJECT_ID} \ | ||
| --member="serviceAccount:fullsend-runner@${ANTHROPIC_VERTEX_PROJECT_ID}.iam.gserviceaccount.com" \ | ||
| --role="roles/aiplatform.user" \ | ||
| --condition=None | ||
| ``` | ||
|
|
||
| 3. **Create and download a JSON key**: | ||
| ```bash | ||
| gcloud iam service-accounts keys create /tmp/sa-key.json \ | ||
| --iam-account=fullsend-runner@${ANTHROPIC_VERTEX_PROJECT_ID}.iam.gserviceaccount.com | ||
| ``` | ||
|
|
||
| 4. **Set the secrets on the `.fullsend` repo** (where the workflow runs): | ||
| ```bash | ||
| gh secret set GCP_SA_KEY --repo your-org/.fullsend < /tmp/sa-key.json | ||
| gh secret set GCP_PROJECT --repo your-org/.fullsend --body "${ANTHROPIC_VERTEX_PROJECT_ID}" | ||
| gh secret set GCP_REGION --repo your-org/.fullsend --body "${CLOUD_ML_REGION}" | ||
| ``` | ||
|
|
||
| 5. **Delete the local key file** (it's now stored as a GitHub secret): | ||
| ```bash | ||
| rm /tmp/sa-key.json | ||
| ``` | ||
|
|
||
| Available regions for Claude on Vertex AI include `us-east5`, `europe-west1`, and `asia-southeast1`. Check the [Vertex AI documentation](https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-claude#regions) for the latest list. | ||
|
|
||
| ### GitHub Actions runner | ||
|
|
||
| The workflow installs these automatically: | ||
|
|
||
| - **fullsend** binary (from a GitHub release) | ||
| - **OpenShell** CLI | ||
|
|
||
| Claude Code and experiment tool binaries are pre-installed in the container image (`quay.io/manonru/fullsend-exp`), which the sandbox is created from via `--from`. | ||
|
|
||
| ## Quick start (using defaults) | ||
|
|
||
| ```bash | ||
| # Clone the .fullsend repo (one-time setup) | ||
| git clone git@github.com:test-fullsend/.fullsend.git /tmp/dot-fullsend | ||
|
|
||
| # Run the experiment (builds image, pushes to quay.io, syncs, triggers workflow) | ||
| ./experiments/runner-hello-world/experiment/run-experiment.sh | ||
| ``` | ||
|
|
||
| The script will print the workflow run URL. You can watch it with: | ||
|
|
||
| ```bash | ||
| gh run watch <RUN_ID> --repo test-fullsend/.fullsend | ||
| ``` | ||
|
|
||
| ## Using a different org | ||
|
|
||
| To run against your own org, edit the variables at the top of `experiment/run-experiment.sh`: | ||
|
|
||
| ```bash | ||
| FULLSEND_REPO="/tmp/your-dot-fullsend" # Local clone of your .fullsend repo | ||
| RELEASE_REPO="your-user/fullsend" # Where to upload the fullsend binary | ||
| RELEASE_TAG="runner-hello-world-dev" # Release tag name | ||
| WORKFLOW_REPO="your-org/.fullsend" # Where to trigger the workflow | ||
| WORKFLOW_FILE="hello-world.yml" # Workflow file name | ||
| TARGET_REPO="your-org/your-target-repo" # Target repo for the agent | ||
| IMAGE_REPO="quay.io/your-user/your-image" # Container image registry | ||
| ``` | ||
|
|
||
| Then update the workflow file (`experiment/workflow/hello-world.yml`) to point the fullsend install step at your release: | ||
|
|
||
| ```yaml | ||
| - name: Install fullsend | ||
| run: | | ||
| curl -LsSf https://github.com/your-user/fullsend/releases/download/runner-hello-world-dev/fullsend_dev_linux_amd64.tar.gz -o /tmp/fullsend.tar.gz | ||
| sudo tar xzf /tmp/fullsend.tar.gz -C /usr/local/bin/ | ||
| ``` | ||
|
|
||
| Steps: | ||
|
|
||
| 1. Create two repos in your org: `.fullsend` and a target repo with some content | ||
| 2. Create a GitHub release on your fullsend fork: `gh release create runner-hello-world-dev --repo your-user/fullsend --title "Dev" --notes "Dev build"` | ||
| 3. Set the required secrets on the `.fullsend` repo (see [Setting up GCP secrets](#setting-up-gcp-secrets)) | ||
| 4. Clone the `.fullsend` repo locally: `git clone git@github.com:your-org/.fullsend.git /tmp/your-dot-fullsend` | ||
| 5. Run `./experiments/runner-hello-world/experiment/run-experiment.sh` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| # How to run `fullsend run` locally | ||
|
|
||
| This guide explains how to run the `fullsend run` CLI command on your local machine against a target repository. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - **Go toolchain** (1.23+) | ||
| - **OpenShell** installed and in PATH | ||
| - **Docker** (required by OpenShell — Podman is not supported) | ||
| - **GCP credentials** for Vertex AI (if using the hello-world experiment) | ||
|
|
||
| ## Install Docker | ||
|
|
||
| OpenShell requires Docker. Podman is not supported. Install Docker CE and make sure the daemon is running: | ||
|
|
||
| ```bash | ||
| # Fedora | ||
| sudo dnf config-manager addrepo --from-repofile=https://download.docker.com/linux/fedora/docker-ce.repo | ||
| sudo dnf install -y docker-ce docker-ce-cli containerd.io | ||
|
|
||
| # Start the daemon | ||
| sudo systemctl start docker | ||
| sudo systemctl enable docker | ||
|
|
||
| # Allow your user to run docker without sudo | ||
| sudo usermod -aG docker $USER | ||
| newgrp docker | ||
|
|
||
| # Verify | ||
| docker info | ||
| ``` | ||
|
|
||
| ## Install OpenShell | ||
|
|
||
| ```bash | ||
| curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/v0.0.30/install.sh | sh | ||
| openshell --version | ||
| ``` | ||
|
|
||
| ## Build fullsend | ||
|
|
||
| From the repository root: | ||
|
|
||
| ```bash | ||
| go build -o ~/.local/bin/fullsend ./cmd/fullsend/ | ||
| fullsend --version | ||
| ``` | ||
|
|
||
| ## Required environment variables | ||
|
|
||
| The hello-world experiment requires these environment variables on the host: | ||
|
|
||
| | Variable | Purpose | | ||
| |----------|---------| | ||
| | `ANTHROPIC_VERTEX_PROJECT_ID` | GCP project with Vertex AI API enabled | | ||
| | `CLOUD_ML_REGION` | GCP region (e.g. `us-east5`, `europe-west1`) | | ||
| | `GOOGLE_APPLICATION_CREDENTIALS` | Path to GCP service account key JSON | | ||
|
|
||
| If you already use Claude Code via Vertex AI locally, `ANTHROPIC_VERTEX_PROJECT_ID` and `CLOUD_ML_REGION` are likely already set. For `GOOGLE_APPLICATION_CREDENTIALS`, you can use a service account key file or the Application Default Credentials from gcloud: | ||
|
|
||
| ```bash | ||
| gcloud auth application-default login | ||
| export GOOGLE_APPLICATION_CREDENTIALS=~/.config/gcloud/application_default_credentials.json | ||
| ``` | ||
|
|
||
| ## Pre-pull the sandbox image | ||
|
|
||
| The first sandbox creation will time out if the image hasn't been pulled yet. Pull it in advance: | ||
|
|
||
| ```bash | ||
| docker pull quay.io/manonru/fullsend-exp:latest | ||
| ``` | ||
|
|
||
| ## Running the agent | ||
|
|
||
| ```bash | ||
| fullsend run hello-world \ | ||
| --fullsend-dir /path/to/experiments/runner-hello-world/.fullsend \ | ||
| --target-repo /path/to/your-repo \ | ||
| --output-dir /tmp/fullsend-output | ||
| ``` | ||
|
|
||
| ### CLI flags | ||
|
|
||
| | Flag | Required | Default | Purpose | | ||
| |------|----------|---------|---------| | ||
| | `--fullsend-dir` | yes | | Base directory containing the `.fullsend` layout | | ||
| | `--target-repo` | yes | | Path to the target repository | | ||
| | `--output-dir` | no | `/tmp/fullsend` | Base directory for run output (per-invocation subdirectories are created under it) | | ||
|
|
||
| ## Inspecting results | ||
|
|
||
| After a run, output is organized under the `--output-dir` directory: | ||
|
|
||
| ``` | ||
| /tmp/fullsend-output/ | ||
| agent-hello-world-<pid>-<timestamp>/ | ||
| iteration-1/ | ||
| output/ # Files the agent produced (hello-world.md, summary.md) | ||
| transcripts/ # Claude transcript .jsonl files | ||
| iteration-2/ # Only if validation retried | ||
| output/ | ||
| transcripts/ | ||
| ``` | ||
|
|
||
| The CLI prints the full run directory path at the end: | ||
|
|
||
| ``` | ||
| Run directory /tmp/fullsend-output/agent-hello-world-12345-1713200000 | ||
| Agent exit code 0 | ||
| Agent runs 1 | ||
| Validation passed | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| - **"openshell not found in PATH"**: Install OpenShell (see above). | ||
| - **"sandbox not ready after 1m0s"**: The sandbox image hasn't been pulled yet. Run `docker pull quay.io/manonru/fullsend-exp:latest` first (see above). | ||
| - **"Docker socket exists but the daemon is not responding"**: Run `sudo systemctl start docker`. | ||
| - **"permission denied while trying to connect to the Docker daemon"**: Your user is not in the `docker` group. Run `sudo usermod -aG docker $USER` and start a new shell session. | ||
| - **"host variable X is not set"**: A required environment variable is missing. Check the table above. | ||
| - **Validation failures**: Check `iteration-N/output/` for the agent's output files. The validation script (`scripts/validate-output.sh`) runs on the host and checks for expected files. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.