# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Keep it short. It is loaded into every session in full, so it should carry only
what an agent must know before it has read any code, and point at the file that
owns everything else. Before adding to it, read "Where Knowledge About the Code
Goes" below — most additions belong in a docstring or a nested `CLAUDE.md`.

## Project Overview

Quber extracts tables and structure from financial PDFs and uses LLM analysis to
understand them. The package lives in `src/quber/`; `experiments/` is prototypes
and is not part of it.

Dependency versions live in `pyproject.toml`, resolved in `uv.lock`. That is the
single source of truth — never state a dependency version in documentation.

## Extraction Pipeline (Canonical Configuration)

The default docling configuration is the `tuned-financial` preset
(TableFormerMode.ACCURATE, DoclingParse backend, picture classification,
accelerator device resolved automatically, `page_batch_size=32`). The preset is defined in
`src/quber/core/parsers/docling_parser.py` — that code is the source of
truth for the configuration; see
[`docs/EXTRACTION_PIPELINE.md`](docs/EXTRACTION_PIPELINE.md) for the
rationale and the known docling-level silent gaps it does **not** fix.

Pass `--preset legacy` to `quber document`, `quber fuse`, or `quber analyze` to
revert. `quber parse` is a retained alias for `quber document`.

The four pipeline commands and the artifacts they hand between each other are
documented in the module docstring of `src/quber/cli.py`.

## Development Commands

```bash
uv sync --all-extras          # dependencies, including dev extras
pytest                        # tests
pytest --cov=quber            # tests with coverage
pre-commit install            # once
pre-commit run --all-files    # ruff, pyright, validate-pyproject
```

Run the CLI with `uv run quber <command>`. Development happens on the host —
there is no container for it. The two images the project ships are built in CI
from a tag: `deploy/Dockerfile` for the cloud job and `runpod/Dockerfile` for
the GPU worker.

## Where Knowledge About the Code Goes

Two homes, chosen by what the knowledge is about.

**How the code composes belongs in a docstring.** A module docstring for one
file, a package `__init__.py` docstring for how the modules inside it fit
together. A docstring is read for free by anyone who opens the file, and it
appears in the diff when the behavior changes, so it gets reviewed alongside the
code it describes. `src/quber/core/extractors/set_of_mark/__init__.py` states
how the three extraction stages constrain each other.
`src/quber/core/__init__.py` carries the import discipline that keeps the GPU
stack out of the CPU-only path. `src/quber/cli.py` carries the artifact contract
between the four pipeline commands.

**How to work on the code belongs in a `CLAUDE.md` in that directory.** Where
the traces and output artifacts live, how to gather evidence before forming a
diagnosis, and which limitations are the accepted baseline rather than a new
bug. `src/quber/core/extractors/set_of_mark/CLAUDE.md` is the model to follow.
A nested `CLAUDE.md` loads only when a file in its directory is opened, so put
one where the work actually happens.

Never restate in prose what the code already states. A description of what a
function does goes stale the moment someone edits it, and it is derivable from
the file faster than anyone can maintain the copy. Write ownership and
invariants instead — which component decides what, and what has to stay true —
because those survive a refactor that moves every line.

The same applies between documents. When one file owns a list, a format, or a
rule, every other file points at it and none of them copy it. A copy always
drifts, and the drift is invisible until an agent acts on the stale one.

`docs/` holds design records and studies written for people to read. They are
not agent reference material, they are not kept in step with the code, and a
claim in one is not authoritative over the code it describes.

## Workflow Source of Truth

**Jira is the primary tracking system** (project key `QUE`). GitHub PRs reference Jira tickets. This repo does not use GitHub Issues.

All workflow specifications live in two documents — read them before doing issue or PR work:

- **`docs/ISSUES_SPEC.md`** — Jira issue types, templates, title conventions, status workflow, validation, evidence requirements
- **`docs/GITHUB_WORKFLOW_SPEC.md`** — branch naming, PR title format, PR body structure, functional evidence requirements, merge strategies, Jira integration

These specs override any inline mechanics described elsewhere in this file.

## Issue and PR Delegation

Two subagents handle all tracking-system operations. The main agent has no direct access to `gh`, the GitHub MCP, or Jira APIs (denied in `.claude/settings.json`):

- **`jira-workflow`** — all Jira operations (create/update/search issues, comments, epic linking). Source of truth: `docs/ISSUES_SPEC.md`.
- **`github-workflow`** — all GitHub PR operations (create/list/get PRs, PR comments). Source of truth: `docs/GITHUB_WORKFLOW_SPEC.md`.

**Never instruct `jira-workflow` to transition a Jira issue's status unless the user explicitly asked for that move.** Don't auto-transition on PR creation or any other convention.

The line is whether a recipe governs the operation, not whether it reaches GitHub. Plain git is the main agent's own work: `status`, `diff`, `log`, `branch`, `add`, `commit`, `push`, worktrees. Anything shaped by a template or a spec goes to the specialist — pull requests, issue bodies, comments, evidence formatting, status transitions, and the scripts that carry them out.

Keep the *work content* — code, analysis, decisions — and hand off the *workflow mechanics*. Before delegating, gather issue type, title, conversation context, parent epic or story, priority, and for PRs the test evidence as command, PASS/FAIL, and output. The subagent will refuse to create a PR without evidence.

**Always delegate** — never invoke `gh issue comment`, `gh pr comment`, `curl ...atlassian...`, or the operations Skills directly. The settings will block them; even if they didn't, the subagents enforce template and evidence consistency.

Those agents can only do what the scripts under `.claude/skills/*/scripts/` wrap, because `permissions.deny` blocks raw `gh` and Atlassian calls for every agent in the session — per-agent permissions do not exist. When an operation is missing, do not work around it and do not write the script yourself. Each agent owns the scripts of its own Skill, and every new wrapper is surfaced to the user before it is written — read-only ones included. A missing operation is a question to raise, not latitude to take: say what is missing and what the wrapper would run, and wait. When the answer is no, report what could not be determined rather than inferring it another way.

`.github/workflows/jira-transition.yml` is the only tracking automation. It fires on branch creation and on a PR opening or closing. There is no GitHub Project board and no `status:*` labels — status lives in Jira.

## Pull Request Issue Resolution Workflow

When addressing issues raised in PR comments or reviews, follow this loop:

1. **Replicate** — Run the failing command/build/test locally; capture output. If you can't replicate, state why explicitly.
2. **Address** — Implement the targeted fix. Keep changes minimal.
3. **Test** — Re-run the same command/build/test; capture output. If you can't test, state why and what testing is recommended.
4. **Post update** — Delegate to `github-workflow` to comment on the PR with: acknowledgment, replication evidence, root cause, what changed (files/lines), test results, next steps.

Never skip replication or testing when they are possible. The user needs evidence the fix works, not assurances.

**Never create a PR without running tests and documenting results.** The required format and the broader functional evidence requirements live in `docs/GITHUB_WORKFLOW_SPEC.md` → "Functional Evidence Requirements" and `docs/ENGINEERING_STANDARDS.md` → "Functional Evidence" and "Definition of Done".

## PydanticAI Documentation Reference

Answer PydanticAI questions from existing knowledge. Delegate to the
`pydanticai-logfire-docs` subagent only to verify current behavior: a runtime
error suggesting an API change, a question about which models are available, or
an explicit request for current docs. Its own definition in
`.claude/agents/pydanticai-logfire-docs.md` sets its scope.

# Reminders

Never write a documentation file unless asked for one. Never use an emoji
anywhere — code, logs, generated text, commit messages.

## CRITICAL Git Workflow Rules

**ABSOLUTE REQUIREMENTS — NO EXCEPTIONS:**

1. **NEVER commit directly to main** — Only allowed when the user explicitly authorizes.
2. **Each Jira ticket gets its own branch** — Never combine multiple tickets into one branch unless explicitly instructed.
3. **All changes require a PR with test evidence** — No exceptions, no PRs without evidence.
4. **NEVER close issues that have a pending PR** — That is self-signoff. The user reviews, merges, and closes.
5. **Never skip git hooks or signing** — `--no-verify` / `--no-gpg-sign` are off-limits unless the user explicitly asks.

Branch naming, commit message format, PR title format, PR body structure, and merge strategy are all defined in **`docs/GITHUB_WORKFLOW_SPEC.md`**. Read it before creating branches or PRs. Summary:

- Branches: `<type>/QUE-XXX-brief-description` — the spec's "Branch Types" section is the only list of valid types
- PR title: `QUE-XXX: Brief description`
- PR body: Summary, related Jira issue, AC functional evidence, test evidence, changes made

**If you can't comply, STOP and ask the user.**

## Git Worktrees

Work on more than one ticket at a time in sibling worktrees, one per ticket:

```bash
git worktree add -b <type>/QUE-56-<description> ../quber-QUE-56
cd ../quber-QUE-56
ln -s "$(git rev-parse --show-toplevel)/.env" .env
uv sync --all-extras
```

Two project-specific rules the git defaults don't give you:

- **Each worktree gets its own `.venv`.** They are never shared, so dependency
  upgrades can be tested in isolation and concurrent `uv sync` runs cannot
  collide over the lock.
- **Only `.env` is shared**, by symlink to the main worktree, so API keys live in
  one place. Find the main worktree with `git rev-parse --show-toplevel` rather
  than a hardcoded path.

After the PR merges, `git worktree remove ../quber-QUE-56 && git worktree prune`.

## Standing User Instructions

- Never make unsolicited assessments about what content is "acceptable" to omit, drop, or de-prioritize. If this is a financial document and the critical items land on a page that failed extraction, the legal liability falls on us — we have no defense. Surface failures explicitly; do not silently judge.
- **Answer only what was asked; do not volunteer unverified claims or unrequested scope.** Three failures to avoid every turn:
  1. *Unconfirmable assertions* — never state a fact you have not verified this session (how code behaves, performance, cost, what is "safe/free/expensive"). Ground it in a file you read or a command you ran, or do not say it.
  2. *Unconsented additions* — no optimizations, refactors, extra design points, or scope the user did not request. If you think one matters, raise it as a one-line question, not as a fait accompli.
  3. *Distractions / editorializing* — if a sentence is neither a direct answer to the question nor backed by evidence you can point to, cut it.
  A wrong or unverifiable aside is expensive: it derails the thread and forces the user to spend a turn correcting you. When in doubt, say less and ask.
- **Close substantial work with a status report, as a deliberate final pass.** Never a chronological narrative of what you did — a contemporaneous stream with successes and failures interleaved as you hit them is impossible to parse. Organize by kind, not by time: group all successes together and all failures together, and never alternate between them. Lead with the most consequential finding, even when it is not the answer to the question asked. Bold lead-in, then a couple of sentences. Counts over adjectives. State which claims are not evidence on their own and how you verified them separately. Include your own process errors, not just code defects. Distinguish untested from broken.
