# P5c task 02: `sift extract ` **Branch:** `p5c` (`git switch p5c`; `git status --short` must be empty, otherwise stop) **Commit subject:** `cli: sift extract uploads a local PDF; README and skill` ## Goal `sift extract thesis.pdf [--pages 41-60] [--grep RE] [--question Q] [--json]` uploads the file to `/v1/extract` and prints the answer exactly as `sift fetch` does. ## Files - Copy: `cmd/sift/extract_test.go` - Create: `cmd/sift/extractcmd.go` - Modify: `cmd/sift/main.go` (a `case "extract":` and one help line), `README.md`, `skill/SKILL.md`, `docs/implementer-log.md` ## Interfaces ```go package main type extractOpts struct { File, Pages, Grep, Question, Mode string JSON bool } const extractUsage = "usage: sift extract [--pages a-b] [--grep RE] [--question Q] [--mode clean|digest] [--json]" func parseExtractOpts(args []string) (extractOpts, error) // flags before or after the file, as fetch func extractURL(base string, o extractOpts) string // base + "/v1/extract?" + only the options that are set; mode=digest when Question is set and Mode is empty ``` ## Rules 1. The command: - Resolve the base URL and key exactly as `sift fetch` does (reuse its client-config helpers; do not copy them). - `stat` the file: over 100 MiB → exit with a message before uploading. - `POST` the bytes with `Content-Type: application/pdf` and the bearer key. - Print `content` (or the whole envelope with `--json`), with the same errors and exit codes as fetch (`exitFor`). - Do not read the whole file into memory twice: stream it with `os.Open` as the request body and set `ContentLength`. 2. **`README.md`:** a `sift extract` subsection next to `sift fetch`. 3. **`skill/SKILL.md`:** "A PDF on disk (an attachment, a download): `sift extract `, with the same `--pages`/`--grep`/`--question`. Never run `pdftotext` yourself." ## Steps - [ ] **1.** `git switch p5c`; copy the given test. **2. See it fail.** - [ ] **3.** `extractcmd.go`, `main.go`, README, skill. - [ ] **4.** `gofmt -w`; `go test -race -count=3 ./cmd/sift/` → `ok`. **5.** `make gate`. - [ ] **6.** `make build && bin/sift extract 2>&1 | head -1` prints the usage line. - [ ] **7.** Row `p5c/02-extract-cli`; commit. ```sh git add cmd/sift README.md skill/SKILL.md docs/implementer-log.md git commit -F .state/commit-msg.txt ``` ## Done when - All tests pass; `make gate` ok; given file byte-identical.