# CI Log Fetcher

**Agent:** `ci-log-fetcher`
**Location:** `.opencode/agents/ci-log-fetcher.md`

The `ci-log-fetcher` agent retrieves CI job logs from Forgejo Actions using
web authentication. It is a **read-only utility agent** used by all PR-related
agents to access CI failure details without manual web scraping.

> **Key rule:** Callers **must not** pass `forgejo_username` or
> `forgejo_password` parameters. The agent reads `FORGEJO_USERNAME` and
> `FORGEJO_PASSWORD` from environment variables automatically.

---

## Purpose

When a PR has failing CI, agents need to read the raw log output to understand
what went wrong. The Forgejo Actions API does not expose logs in a
machine-readable way that is easy to parse, so `ci-log-fetcher` handles the
authentication and log retrieval workflow, returning the raw log text to the
caller.

---

## Usage

```yaml
# In an agent definition — grant permission to call ci-log-fetcher
permissions:
  - ci-log-fetcher
```

```
# In agent prompt / instructions
To get CI logs for PR #1234, job "unit-tests":
  Use the ci-log-fetcher subagent with:
    pr_number: 1234
    job_name: unit-tests
    repository: cleveragents/cleveragents-core
  
  DO NOT pass forgejo_username or forgejo_password — the agent
  handles credentials automatically from environment variables.
```

### Parameters

| Parameter | Required | Description |
|-----------|----------|-------------|
| `pr_number` | Yes | The PR number to fetch logs for |
| `job_name` | Yes | The CI job name (e.g. `unit-tests`, `integration-tests`) |
| `repository` | Yes | `owner/repo` format (e.g. `cleveragents/cleveragents-core`) |

### Common job names

| Job | `job_name` value |
|-----|-----------------|
| Unit tests | `unit-tests` or `unit_tests` |
| Integration tests | `integration-tests` or `integration_tests` |
| Lint | `lint` |
| Typecheck | `typecheck` |
| Security scan | `security-scan` or `security_scan` |
| Coverage | `coverage` |

The agent normalises job names (converts `-` to `_` and vice versa) when
looking up the job in the PR's check runs.

---

## Optimised Workflow

The agent follows a tested, optimised workflow that minimises execution time
(~5 seconds vs. ~30 seconds for naive approaches):

```
1. Load PR page: GET /cleveragents/cleveragents-core/pulls/{pr_number}
   → Extracts all CI check run links directly from the page HTML.
   → No separate API calls needed to find job IDs.

2. Find the matching job link by normalised job name.

3. Fetch logs: GET /actions/runs/{run_id}/jobs/{job_id}/attempt/{attempt}/logs
   → Uses attempt=1 on first try (correct ~95% of the time).
   → Falls back to attempt=2 if 404.

4. Return raw log text to caller.
```

**What the agent does NOT do (saves time):**
- Does not call `/api/v1/repos/.../actions/runs` (always returns 404 for logs)
- Does not look up CSRF tokens (Forgejo login does not use them)
- Does not make multiple API calls to discover job IDs

---

## Authentication

The agent uses **web session authentication** (not the Forgejo API token):

1. `POST https://git.cleverthis.com/user/login` with `FORGEJO_USERNAME` and
   `FORGEJO_PASSWORD` to obtain a session cookie.
2. All subsequent requests use the session cookie.

This is necessary because the Actions log endpoint requires a web session,
not a PAT token.

**Environment variables used:**
- `FORGEJO_USERNAME` — Forgejo username (e.g. `HAL9000`)
- `FORGEJO_PASSWORD` — Forgejo password

Both variables are pre-configured in the build environment. Callers do not
need to provide them.

---

## Output Format

The agent returns the **raw log text** directly — not a JSON wrapper. The
caller receives the full stdout/stderr of the CI job, which can then be
parsed for error messages, test failures, etc.

Example output:
```
2026-04-08T10:23:45Z ##[group]Run nox -s unit_tests
2026-04-08T10:23:45Z + nox -s unit_tests
...
2026-04-08T10:24:12Z FAILED features/session.feature:45 — AssertionError
2026-04-08T10:24:12Z 1 feature passed, 0 failed, 1 error
```

---

## Agents That Use ci-log-fetcher

All PR-related agents call `ci-log-fetcher` instead of implementing their own
CI log retrieval:

| Agent | When it calls ci-log-fetcher |
|-------|------------------------------|
| `pr-checker` | After CI fails on a PR being monitored |
| `implementation-worker` | In `pr-fix` mode, to understand CI failures |
| `pr-fix-orchestrator` | To analyse failures before dispatching fix workers |
| `pr-self-reviewer` | To check CI status before reviewing |
| `human-liaison` | When responding to PR comments about CI failures |
| `pr-status-checker` | When `include_logs=true` is requested |
| `system-watchdog` | In Audit 9 (test health) for emergency test-skip response |

---

## Performance Notes

| Metric | Value |
|--------|-------|
| Typical execution time | ~5 seconds |
| Previous execution time (before optimisation) | ~30 seconds |
| Improvement | ~85% reduction |

The main savings come from:
- Parsing job links from the PR page (1 request) instead of multi-step API
  lookups (4–6 requests)
- Skipping CSRF token lookup (saves ~2 s)
- Using the correct log endpoint pattern on the first attempt (saves retries)

---

## Troubleshooting

**"Job not found" error:**
- Check that `job_name` matches one of the job names in the PR's check runs.
- Try both hyphenated and underscored variants (e.g. `unit-tests` vs `unit_tests`).
- The agent normalises names, but the PR page must have a matching check run.

**"Authentication failed" error:**
- Verify `FORGEJO_USERNAME` and `FORGEJO_PASSWORD` are set in the environment.
- The agent will log which credential source it is using (env vars vs parameters).

**Empty log output:**
- The job may not have produced any output (e.g. it was skipped or cancelled).
- Try fetching a different attempt number by checking the PR page manually.

---

## Related Documentation

- [CI/CD Pipeline](../development/ci-cd.md) — pipeline architecture
- [System Watchdog](../development/system-watchdog.md) — uses ci-log-fetcher for emergency test-skip
- [Quality Automation](../development/quality-automation.md) — CI quality gates
