Skip to content

Skills · dev-team

codebase-tour

Get a newcomer (a new engineer, or the agent itself) oriented in an unfamiliar repository before they make one specific change, with a short tour scoped to that change. It gives the install, run and test commands taken from CI, package scripts and the Makefile; the path the change touches, traced through the code with file:line citations; where the change goes; the conventions the code actually follows; the traps (generated files, a second copy of the logic, untested code, env vars, flags); and a first step that can be checked. Use when someone says "I'm new to this repo", "get me oriented", "where would I make this change", "walk me through the code for X", "onboard me before I start this ticket", or "how do I run and test this".

Pack dev-teamTier standardJob Build and review softwarev0.1.1

npx skilldrop-cli install codebase-tour
Other ways to install

With the sibling skills it hands off to:

npx skilldrop-cli install codebase-tour --with-related

The whole pack it belongs to:

npx skilldrop-cli install --pack dev-team

By hand, from a clone of the repo:

cp -R packs/dev-team/skills/codebase-tour ~/.claude/skills/

In Claude Code, with the dev-team plugin installed, invoke it as:

/dev-team:codebase-tour

Try it

A realistic prompt from the skill's acceptance evals:

I'm new to this repo (it's the current directory) and my first ticket is to add a `carrier` filter to GET /shipments, so dispatchers can see one carrier's shipments at a time. Get me oriented before I start: how to run it, where the change goes, and anything that will bite me.

What a good result looks like

Example output

Worked example: tallyhall, before adding a refund window · the skill's own worked example, source

Input

A fictional FastAPI ticketing service. The README is two releases stale, one rule has a second copy, and one module is generated.

I've just joined and my first ticket is "refunds must be requested within 14 days of the event ending". I've never opened this repo. Get me oriented. The repo is the current directory.

The files that mattered, with the line numbers the tour cites:

README.md
  5   ## Run it
  7       make dev
 12   Settings live in `settings.toml`.

Makefile
  1   .PHONY: run test lint
  3   run:
  4   	uvicorn tallyhall.main:app --reload
  7   test:
  8   	pytest -q -m "not e2e"
 10   lint:
 11   	ruff check tallyhall tests

.github/workflows/ci.yml
 17         - run: pip install -e ".[dev]"
 19         - run: make lint
 21         - run: make test
 23     env:
 24       TALLYHALL_DB_URL: sqlite:///ci.db

pyproject.toml
 14   [tool.pytest.ini_options]
 15   markers = ["e2e: needs the payment sandbox"]

tallyhall/main.py
  6   app = FastAPI()
  7   app.include_router(refunds.router)

tallyhall/api/refunds.py
 18   @router.post("/orders/{order_id}/refunds", status_code=201)
 19   def create_refund(order_id: int, db=Depends(get_db)):
 20       order = orders.get(db, order_id)
 22       check_refundable(order, now=utcnow())
 24       except RefundRejected as e:
 25           raise HTTPException(422, {"code": e.code, "message": str(e)})
 27       return refunds.create(db, order)

tallyhall/rules/refunds.py
  4   class RefundRejected(Exception):
  9   def check_refundable(order, now):
 10       if order.status != "paid":
 11           raise RefundRejected("not_paid", "only paid orders can be refunded")
 12       if order.refunded_at is not None:
 13           raise RefundRejected("already_refunded", "order already refunded")

tallyhall/admin/bulk_refund.py
 27       if order.status == "paid" and order.refunded_at is None:
 28           refunds.create(db, order)

tallyhall/models_gen.py
  1   # generated by datamodel-codegen:
  2   #   filename:  schemas/order.json

tallyhall/settings.py
  6   DB_URL = os.environ["TALLYHALL_DB_URL"]

tests/rules/test_refunds.py   (test_rejects_unpaid, test_rejects_already_refunded)
tests/api/test_refunds_e2e.py (marked e2e)

The fact lister also reported: make dev named at README.md:7 with no dev target in the Makefile, and settings.toml named at README.md:12 and not present. No test file imports tallyhall/admin/bulk_refund.py. The Order model (tallyhall/models_gen.py) has an event_ends_at field.

Output

Output

What matters for this change

  • The rule goes in check_refundable (tallyhall/rules/refunds.py:9). Every other refund rule lives there, and the API calls it at tallyhall/api/refunds.py:22.
  • There is a second copy of the refund rules in the support bulk-refund tool (tallyhall/admin/bulk_refund.py:27). It doesn't call check_refundable, so it won't pick up the window unless someone changes it. Whether it should is the first question for a maintainer.
  • Ignore the README's make dev and settings.toml. Neither exists. Run with make run (Makefile:3); settings come from env vars (tallyhall/settings.py:6).
  • tallyhall/models_gen.py is generated from schemas/order.json. Don't edit it. The field the window needs, event_ends_at, is already there.
  • make test skips the e2e tests (Makefile:8, marker at pyproject.toml:15). The rule tests in tests/rules/ do run.

Tour: tallyhall, for "refunds within 14 days of the event ending"

Read on 2026-10-20. Scope: POST /orders/{order_id}/refunds from the app bootstrap to refunds.create. Skipped on purpose: ticket purchase, the payment-provider client, deployment config.

[assumption] "Within 14 days of the event ending" means now - order.event_ends_at <= 14 days, with the boundary day allowed.

Run it

ToCommandSourceStatus
Installpip install -e ".[dev]".github/workflows/ci.yml:17read, not run
Test (whole suite)make test → pytest -q -m "not e2e".github/workflows/ci.yml:21, Makefile:8ran: passed (14 passed, 3 deselected)
Test (this area)pytest -q -m "not e2e" tests/rules/test_refunds.pyderived from Makefile:8ran: passed (2 passed)
Lintmake lint → ruff check tallyhall tests.github/workflows/ci.yml:19, Makefile:11ran: passed
Run locallymake runMakefile:3read, not run (needs TALLYHALL_DB_URL)

Needs: TALLYHALL_DB_URL, read at tallyhall/settings.py:6 with no default; CI sets sqlite:///ci.db at .github/workflows/ci.yml:24.

The path this change touches

  1. tallyhall/main.py:7: the refunds router is mounted on the app.
  2. tallyhall/api/refunds.py:19 create_refund: loads the order (line 20).
  3. tallyhall/api/refunds.py:22: calls check_refundable(order, now=utcnow()).
  4. tallyhall/rules/refunds.py:9 check_refundable: raises RefundRejected for an unpaid order (line 10) or one already refunded (line 12).
  5. tallyhall/api/refunds.py:25: RefundRejected becomes a 422 with {code, message}.
  6. tallyhall/api/refunds.py:27: refunds.create writes the refund. This is the far edge.

Where the change goes

  • tallyhall/rules/refunds.py check_refundable: add the window check after line 13, raising RefundRejected("refund_window_closed", …). This follows the two rules already there.
  • Must change with it: nothing generated. event_ends_at already exists in tallyhall/models_gen.py. Whether tallyhall/admin/bulk_refund.py:27 changes too is open (question 1).

Conventions the code follows

  • Errors: a rule raises RefundRejected(code, message) with a snake_case code (tallyhall/rules/refunds.py:11); the route maps it to 422 (tallyhall/api/refunds.py:25).
  • Time: the route passes now in, so rules are tested without a clock (tallyhall/api/refunds.py:22).
  • Tests: one test_rejects_<reason> per rule, under tests/rules/ (tests/rules/test_refunds.py).
  • Config: env vars read in tallyhall/settings.py; a missing var fails at import (tallyhall/settings.py:6).

Traps

  • Generated: tallyhall/models_gen.py from schemas/order.json (tallyhall/models_gen.py:1-2). No regenerate command is defined in the Makefile, pyproject or CI; see question 2. CI drift check: none found.
  • Second copy: tallyhall/admin/bulk_refund.py:27 repeats the paid and not-refunded checks inline.
  • Untested on the path: none on the API path. Off the path, tallyhall/admin/bulk_refund.py has no test.
  • Tests the default command skips: e2e (Makefile:8, pyproject.toml:15): tests/api/test_refunds_e2e.py, which needs the payment sandbox.
  • Env vars and flags on the path: TALLYHALL_DB_URL only. No feature flags found.
  • Vendored: none.

Where the README is wrong

  • README says make dev (README.md:7); the Makefile has run, test and lint only (Makefile:1). Use make run.
  • README says settings live in settings.toml (README.md:12); there is no such file, and settings are env vars (tallyhall/settings.py:6).

Tests for this area

  • Covered by: tests/rules/test_refunds.py (unpaid and already-refunded rejections).
  • Run just these: pytest -q -m "not e2e" tests/rules/test_refunds.py (derived from Makefile:8).
  • Not covered: the 422 mapping is exercised only by the e2e test, which make test skips.

First step

Add test_rejects_refund_after_window to tests/rules/test_refunds.py, with an order whose event_ends_at is 15 days before now. Run pytest -q -m "not e2e" tests/rules/test_refunds.py. It fails until check_refundable checks the window. Add a 14-day case that passes, to pin the boundary.

Open questions for a maintainer

  1. Should the bulk-refund tool (tallyhall/admin/bulk_refund.py:27) apply the window, or is it the support override that skips it?
  2. How is tallyhall/models_gen.py regenerated? Nothing in the repo defines the command.
  3. Is the window measured from event_ends_at in UTC? utcnow() is used at tallyhall/api/refunds.py:22, but the schema doesn't say what timezone the event times are in.

Why this passes the bar: every command has a source and a status, both README claims are contradicted with citations, the second copy is named and left as a question rather than silently changed or ignored, the generated file is called out before anyone edits it, and the first step names a file, a command and the failure that proves it.

How it's checked

Measured against plain Claude Code (2026-10-23): it met 85% of its checks, against 45% without it, and a blind judge preferred it. How skills are checked

40 assertions across 5 acceptance evals, and 10 trigger queries. Every skill's checks

What the output must do
  • Opens with a short list of the few things that matter most for this change, before any section, and does not open with a directory listing
  • Every command given is cited to package.json or .github/workflows/ci.yml and marked as either run or only read; npm run dev is not given as a way to run the server
  • Says where the README and the code disagree: there is no dev script (package.json has start:watch), there is no src/routes/ (routes are registered in src/http/routes.ts), and config comes from env vars in src/config.ts, not config/default.json
  • Says the change goes in parseListQuery (src/http/handlers/shipments.ts) and buildShipmentFilter (src/domain/shipments/filter.ts), and that openapi.yaml needs the new query parameter
  • Names src/generated/api-types.ts as generated from openapi.yaml by npm run gen:types, says not to edit it by hand, and notes that CI fails if it drifts (.github/workflows/ci.yml)
  • Names src/jobs/export-shipments.ts as a second copy of the shipment filtering that the change does not reach on its own, notes it has no tests, and raises whether it needs the carrier filter too
  • Names tests/http/shipments.test.ts and tests/domain/filter.test.ts as the tests for the area, with a way to run just those through the repo's vitest script, and notes DATABASE_URL is required to start the server (src/config.ts)
  • Does not invent commands, files, scripts or tools that are not in the repo
  • Says the README is wrong that a new parser module is picked up automatically: the PARSERS registry in src/ledgerline/parsers/__init__.py has to list it
  • Names HEADER_SIGNATURES in src/ledgerline/detect.py as a second place the new bank must be added, or detection fails for the new header
  • Gives the test command from noxfile.py or CI (nox -s tests, nox -s lint tests), says python setup.py test from the README cannot work because there is no setup.py, and notes the tests session skips tests marked slow
  • Gives a way to run a single test file through the runner the repo already uses (nox posargs or pytest), labelled as derived from the repo's config rather than presented as a defined command
  • Points to AcmeParser as the parser to copy and flags that HarborParser has no tests and does not use parse_amount or raise ParseError like the others
  • Identifies src/ledgerline/_version.py as generated by setuptools-scm and not to be edited
  • Each convention it states (ParseError naming the column, money.parse_amount for amounts, CSV samples in tests/fixtures/) is cited to a file in the repo
  • Does not invent commands, files, scripts or tools that are not in the repo
  • Writes docs/backoff-tour.md and modifies no other file in the repo
  • Says the README is wrong about config.yaml: there is no such file, and retry settings are the env vars TIDEPOOL_MAX_ATTEMPTS and TIDEPOOL_RETRY_DELAY read in internal/config/config.go
  • Says the README is wrong that make test includes the database tests: they sit behind the integration build tag and run with make test-integration, which needs Postgres and TIDEPOOL_DATABASE_URL
  • Names Deliver in internal/dispatch/dispatcher.go as where the change goes, and the injectable sleep field used by internal/dispatch/dispatcher_test.go as the way to test the delays
  • Names internal/replay/replay.go as a second retry loop with its own fixed delay that the change must also update or deliberately leave, and notes it has no tests
  • Names internal/store/query.sql.go as generated by sqlc from query.sql, regenerated with make generate, and not to be edited by hand
  • Every command is cited to the Makefile or .github/workflows/ci.yml and marked as run or only read; it does not claim to have run the integration tests
  • Does not invent commands, files, scripts or tools that are not in the repo
  • Gives install/run/test commands taken from the Makefile and .github/workflows/ci.yml (make install / pip install -e ".[dev]", make run / uvicorn shipcalc.main:app, make test / pytest) and explicitly says the README's pip install -r requirements.txt, flask run and python -m unittest discover are stale (there is no requirements.txt and the app is FastAPI, not Flask).
  • Says the EU threshold's source of truth is data/rates.csv (line 2, free_threshold column), that src/shipcalc/generated/rates_table.py is generated (DO NOT EDIT header on line 1) and must not be hand-edited, and that the change is: edit the CSV, then run make gen; it notes that CI's make check-generated step fails if the generated file is out of sync with the CSV.
  • Finds the second, hard-coded copy of the threshold in src/shipcalc/api/preview.py line 5 (FREE_SHIPPING_MIN, used by the /preview/banner route) and says it must also change to 60, or the cart banner and the actual quote will disagree.
  • Traces the quote path with file:line citations: the /quote handler in src/shipcalc/api/routes.py (shipping_cost call at line 24) -> shipping_cost in src/shipcalc/shipping.py (line 13) -> the threshold comparison against RATES[region]["free_threshold"] at shipping.py line 15.
  • Flags the feature flag SHIPCALC_FF_FREE_SHIPPING read in src/shipcalc/shipping.py line 10 (free shipping applies only when it is exactly "on", and it is not in .env.example or the Makefile run target), so a local manual check of the new threshold will show no change unless the flag is set; also notes SHIPCALC_API_KEY is required at startup (src/shipcalc/config.py line 12).
  • Points out that shipping.py and preview.py have no tests while discounts and tax do (tests/unit/test_discounts.py, tests/unit/test_tax.py), and recommends adding boundary tests (e.g. 59.99 vs 60.00 for EU, plus UK/US unchanged) that follow the existing style: pytest functions, Decimal money values, and the flag set via monkeypatch or the environment.
  • Ends with one concrete first step whose result can be checked (e.g. run make test and see it pass before changing anything, or edit the CSV, run make gen and confirm git diff touches only the EU line of rates_table.py), and keeps the tour focused on this ticket instead of walking through tax and discounts in detail.
  • Invents no commands, files, functions or settings that are not in the repo (e.g. no requirements.txt, no python -m shipcalc or flask run as a working command, no existing test_shipping.py, no config value for the threshold outside rates.csv/preview.py).
  • Gives commands from the root package.json and .github/workflows/ci.yml: npm install, npm test (which runs node --test in each workspace), npm run gen / npm run gen:check, and npm run dev:api (which reads ../../.env, so .env must be copied from .env.example first). It says the README's yarn install, cd api && yarn start, yarn test and the api/config.js reference are stale: the repo uses npm workspaces under packages/ and there is no api/ directory or config.js.
  • Identifies packages/api/src/generated/schema.js as generated (DO NOT EDIT on line 1, written by scripts/gen-schema.mjs) and says to change the nights maximum in packages/api/openapi.json (line 24) and run npm run gen, noting that CI's npm run gen:check fails if schema.js is hand-edited or stale.
  • Lists every copy of the 14-night limit that must move to 21: packages/api/openapi.json line 24 (via the regenerated schema.js), packages/api/src/services/bookings.js line 6 (MAX_NIGHTS), and packages/web/src/bookingForm.js line 2 (MAX_NIGHTS, the client-side check). It warns that changing only one of them gives a confusing 400 or 422, or a form that blocks valid stays. The README line also needs updating.
  • Traces the POST /bookings request path with file:line citations: packages/api/src/server.js mounts the router -> packages/api/src/routes/bookings.js line 7 runs validate('BookingRequest') -> packages/api/src/middleware/validate.js line 15 enforces maximum from the generated schema (400) -> createBooking / maxNightsFor in packages/api/src/services/bookings.js enforces MAX_NIGHTS (422).
  • Flags the long-stays feature flag (FEATURE_FLAGS env var parsed in packages/api/src/flags.js; checked at services/bookings.js line 10, giving members LONG_STAY_MAX_NIGHTS = 28). It notes the schema maximum is checked first, so members can never actually reach 28. It asks the ticket owner how the 21-night limit should interact with that flag instead of deciding alone.
  • Notes that services/bookings.js and web/src/bookingForm.js have no tests while pricing and format do (packages/api/test/pricing.test.js, packages/web/test/format.test.js). It warns that a new test importing services/bookings.js will throw unless DATABASE_URL is set, because packages/api/src/db.js lines 2-4 check it at import time, and suggests setting it (plus FEATURE_FLAGS if needed) before a dynamic import, using node:test and node:assert/strict as the existing tests do.
  • Ends with one concrete first step that can be checked (e.g. run npm install && npm test and see 5 passing tests, or change openapi.json, run npm run gen and confirm npm run gen:check passes and the diff shows only the nights maximum), scoped to this ticket.
  • Invents no commands, files, functions or settings that are not in the repo (e.g. no yarn scripts, no api/config.js, no npm run lint or npm run build, no existing bookings test, no .env file claimed to exist).
When it should and shouldn't activate

Should activate:

  • I'm new to this repo and need to add rate limiting to the login endpoint. Get me oriented.
  • Before I start this ticket, walk me through the code that handles invoice exports
  • Where would I make this change? I've never seen this codebase
  • How do I run and test this project, and where does the payment retry logic live?
  • Onboard me to this repo so I can fix the timezone bug in the scheduler

Should leave to another skill:

  • Reverse-engineer the architecture of this whole system and draw the as-is diagram
  • Write an AGENTS.md for this repo so agents stop running the wrong commands
  • Implement the carrier filter on GET /shipments with tests, here are the acceptance criteria
  • Review my diff before I merge it
  • Make an interactive diagram of how a request flows through our services

Hands off to

Related skills

agents-md-generator, architecture-diagrams, interactive-diagram, pre-merge-review, reverse-architecture

Source

SKILL.md · the whole folder on GitHub.