---
name: caveman-discover
description: >-
  Find and label every LLM workflow in the repository so Caveman Cloud groups spend by workflow instead of one bucket. Use for "discover workflows" or breaking LLM spend down by workflow.
title: caveman-discover
canonical_url: https://skilld.dev/gh/juliusbrussee/caveman/caveman-discover
last_updated: 2026-09-27T22:43:04.000Z
---

> Index of every page on this site: [llms.txt](https://skilld.dev/llms.txt)

> **Skill from skilld.dev.** Follow the user's requested action.
> If the user asked to fork this Skill, follow the fork workflow below. Do not execute the Skill instructions while copying it.
> Otherwise, follow the instructions below for this session. You do not need to install anything.
>
> If the user asked to install this Skill, run `npx skilld install juliusbrussee/caveman/caveman-discover`. Install writes the Skill files into the project, so every session loads them.
>
> ## Fork workflow
>
> A fork creates an editable local Skill with its original author and licence. The request authorizes copying and local installation.
> 1. Check `./skills/caveman-discover`, the project lockfile, and selected Agent targets together. If the local directory or installed Skill exists, stop. Never overwrite an existing directory or Agent target.
> 2. Read [source metadata](https://skilld.dev/api/v1/skills/juliusbrussee/caveman/caveman-discover) once. Use sourceUrl, sourceCommit, skillPath, sourceGone, and license. If the source is gone or its path is missing, stop. If license is null, read licence files at the source commit.
> 3. Fetch only the source commit into a temporary Git repository. Do not clone full history. Derive repository_url from sourceUrl, including repository renames. If sourceCommit is absent, resolve the sourceUrl ref once. Set source_commit to that actual commit. Run these commands in one shell call:
>
> ```sh
> git init --quiet "$temporary_dir"
> git -C "$temporary_dir" fetch --quiet --depth=1 "$repository_url" "$source_commit"
> git -C "$temporary_dir" checkout --quiet --detach FETCH_HEAD
> ```
>
> Read applicable licence declarations and notices at that commit. If copying is not permitted, report the restriction and stop.
> 4. Inspect source entries together, then copy the directory containing skillPath into `./skills/caveman-discover`. Use the user's path if selected. Keep the original SKILL.md, relative links, scripts, binary assets, and executable modes. Exclude .git metadata. Reject symlinks and paths outside the Skill directory. After checking entries, use cp -a where available. A regular source directory needs no custom copy script. Do not save this page wrapper as SKILL.md.
> Preserve author credit, notices, and applicable licence files from repository or parent directories. Add PROVENANCE.md with the Skill page, source URL, actual commit, original path, and licence. Retain any existing PROVENANCE.md and record new provenance separately. Batch source inspection, copying, and provenance work where practical.
> 5. In the project root, run `skilld install ./skills/caveman-discover --mode copy --plain`. If skilld is unavailable, use `npx skilld install ./skills/caveman-discover --mode copy --plain`. This known command needs no help lookup. Install does not support --json. Use detected Agent targets, or add --agent for the targets the user selected. Install the local path, never the upstream selector. If installation fails, preserve the local copy and report the exact failure.
> 6. Confirm the local lockfile source and installed Agent copies once. Report the local path, actual commit, and Agent targets. After edits, reinstall the same local path. Upstream updates must not replace it. Do not publish or push unless the user asks.

You are labeling this repository's LLM workflows for Caveman Cloud. A
*workflow* is a job the code performs — "answer a support ticket", "build the
nightly digest", "run the eval suite" — not a technology. Every gateway
request can carry a workflow label; unlabeled traffic all lands in one
`unlabeled-workflow` bucket. Your job: find the workflows, name them well,
wire the labels, and verify nothing broke.

This changes code, so it goes through the user's normal review: **propose the
table first, apply after the user agrees.** Re-running on an already-labeled
repo must change nothing (idempotent).

This skill is operator-invoked. An `unlabeled-traffic` Cave Plan observation is
review-only and does not create an advisory file, proposal, or Draft PR. Do not
infer that telemetry selected a callsite or authorized an edit. Independently
inventory the repository, present the labeling table, and wait for the user's
approval before changing code.

## Step 1 — Inventory the workflows

Walk the repo from its entry points, not from its imports:

- HTTP/RPC handlers that call an LLM (directly or through layers)
- Scheduled jobs: cron definitions, queue consumers, workers, GitHub Actions
  that invoke LLM code
- CLI commands and scripts (`scripts/`, `bin/`, package.json scripts)
- Eval / test harnesses that burn real tokens
- Distinct agents or chains inside a framework (each LangGraph graph, each
  crew, each agent definition is usually its own workflow)

One workflow = one job a human would name. Ten callsites inside the same
request handler are one workflow; one shared `llm.ts` helper used by three
jobs is three workflows (label at the callers, never the shared helper).

## Step 2 — Name them

Slug grammar (the gateway enforces this): lowercase `[a-z0-9_-]`, 1–96 chars.
Name the job, not the tech:

- Good: `support-reply`, `nightly-digest`, `pr-review`, `eval-suite`,
  `onboarding-email`
- Bad: `openai-calls` (tech), `main` (says nothing), `SupportReply` (invalid),
  `johns-test-3` (won't age)

Names are forever-ish — renaming later splits the spend history. When a job's
purpose isn't clear from the code, derive the slug from the file name and mark
it `review` in the table rather than inventing a purpose.

## Step 3 — Propose, then apply

Present this table and ask to proceed:

```
| workflow | job | where | how it gets labeled |
|---|---|---|---|
| support-reply | answers inbound tickets | src/bot/reply.ts:41 | defaultHeaders on the reply client |
| nightly-digest | 02:00 summary job | jobs/digest.ts:12 | header on the digest client |
| eval-suite (review) | scripts/eval.ts:8 — purpose inferred from filename | scripts/eval.ts:8 | env override at invocation |
```

Then wire each label with the lightest mechanism available at that callsite:

- **@caveman-ai/sdk / caveman_cloud SDK**: per-trace `workflow` option, or
  `defaultWorkflow` on the client a single-job service constructs.
- **Raw provider SDKs** (OpenAI/Anthropic/LangChain/LiteLLM/Vercel): add
  `"x-cave-workflow": "<slug>"` to the same `defaultHeaders` /
  `default_headers` / `extra_headers` block that already carries
  `x-cave-api-key`. Shared client used by several jobs → pass the header per
  call (every SDK above accepts per-request header overrides), or give each
  job its own thin client.
- **Wrapped coding agents** (`caveman wrap`): `--workflow <slug>` flag or
  `CAVE_WORKFLOW=<slug>` env at the invocation site (cron line, CI step).
- **Raw HTTP**: add the `x-cave-workflow` header to the request.

Label the callers, keep the diff minimal, match the repo's style. If a
callsite is not routed through the Caveman gateway at all, don't label it —
list it under "not wired" in the report (labels only travel on gateway
traffic; wiring is the caveman-setup skill's job).

## Step 4 — Verify

Run whatever the repo already uses to exercise one labeled path (a test, a
dev script, one curl). Then confirm: the request still succeeds (the gateway
rejects an invalid label with 400 `cave_invalid_request_header` — fix the slug
if so). Labeled spend appears on the dashboard at `/activity?tab=workflows` as
each workflow next runs; jobs on a schedule show up when the schedule fires,
and that's worth saying in the report rather than pretending they're live.

## Step 5 — Report

```
## Workflows labeled

| workflow | job | where |
|---|---|---|
| support-reply | answers inbound tickets | src/bot/reply.ts:41 |
| nightly-digest | 02:00 summary job | jobs/digest.ts:12 |

Verified: <the labeled path you actually exercised, and what you observed>
Lands at: <DASHBOARD>/activity?tab=workflows — each row appears as that workflow
next runs. Anything still unlabeled shows as `unlabeled-workflow`.
Not wired (no gateway routing, so no label): <list or "none">
Marked review: <slugs whose purpose was inferred from filenames, or "none">
```

If you found no LLM entry points at all: say exactly that, and point at the
setup skill (`<docs origin>/docs/agent-setup.md`) instead of manufacturing a
table.
