Conversation
…se) (#29) Establishes the minimum project metadata so subsequent harness tickets have a foundation to land against. - pyproject.toml: name harness-python-react, version 0.1.0, requires-python = ">=3.14", license = "MIT" (PEP 639), seed deps fastapi + pydantic v2. [tool.uv] package = false because src/ does not ship until #17 — this is an application, not a library. - uv.lock: resolved against CPython 3.14.3 (10 transitive deps). - LICENSE: MIT, copyright 2026 Constantinos Koutsakis. - README.md: 2-sentence stub linking to the issue tracker and project board; full README ships in #26. Refs #1
Port the four config blocks from Teller's pyproject.toml. Bump ruff target-version
and mypy python_version to 3.14. Drop duckdb/sse-starlette mypy overrides
(not in template). Add stub package skeleton (src/{api,agent,tools,data,
observability,models,eval}/__init__.py + tests/__init__.py) so import-linter
contracts can resolve before backend tickets land.
Closes #2
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Port .gitignore from Teller (Python-template patterns with anchored /lib/, /dist/, /build/ so frontend subtrees aren't swallowed). Strip Teller-specific lines. Add .editorconfig (LF, UTF-8, 4-space Python, 2-space JS/TS/YAML/Markdown). Add .dockerignore excluding .git/, .github/, .claude/, tests/, docs/, eval/, node_modules/ from the build context. Closes #5 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ne) (#3) (#32) Port .pre-commit-config.yaml from Teller. Bump pinned ruff to v0.15.12 (Teller's v0.11.0 predates py314 target support). Update the JSONC exclude pattern from Svelte's jsconfig.json to TypeScript's tsconfig*.json since the template uses TS. Closes #3 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…frontend-check) (#4) (#33) Port justfile from Teller. Drop Teller-specific banner/comment text. Replace the DuckDB-specific integration-tests comment with a domain-neutral phrasing. Update the docker-build tag from teller:dev to harness-python-react:dev. All recipes use uv run --frozen so lockfile drift is caught loudly. Closes #4 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…) (#34) Port Teller's multi-stage Dockerfile, bump base to python:3.14-slim. Builder materialises the venv via uv sync --frozen --no-dev; runtime copies only the venv + src/ onto a fresh slim base, runs as non-root user `app`. HEALTHCHECK hits /api/v1/health (template's API prefix). Drop the data/ COPY — template has no data dir. UV_PYTHON_DOWNLOADS=never + UV_PYTHON_PREFERENCE=only-system pin to the system Python so pyvenv.cfg symlinks survive the stage handover. Closes #6 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Port docker-compose.yml from Teller. Switch the frontend service from a static nginx build (Teller) to a Vite dev server on port 5173 with bind-mounted source for HMR. Bump OTel env vars from OTEL_ENDPOINT to the standard OTEL_EXPORTER_OTLP_ENDPOINT/OTEL_EXPORTER_OTLP_PROTOCOL/OTEL_SERVICE_NAME triple (matches what the OTel SDK reads in #19). Make .env optional via env_file.path +required:false so first-time `docker compose up` works without a .env file. Closes #7 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Port .github/ISSUE_TEMPLATE/{feature,bug,eval-regression}.md + config.yml,
.github/pull_request_template.md, and .github/CODEOWNERS verbatim from Teller.
Templates are already domain-neutral. CODEOWNERS keeps the solo-owner pattern
(@constk on every path).
Closes #8
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…start) + settings.local.json.example (#15) (#37) Port the three .claude/hooks/*.py scripts and settings.local.json.example verbatim from Teller. Drop .svelte from PRETTIER_EXTENSIONS and add .jsx (template uses React, not Svelte). Strip Teller-specific PR references in comments. Run ruff format on the result. .claude/bash-log.txt and .claude/settings.local.json are already in .gitignore from #5. Closes #15 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Port the six skills from Teller (architect, code-reviewer, devops, frontend, qa-engineer, technical-writer). Strip Teller- and Tomoro-specific references: - "Teller" -> "this project" - frontend skill rewritten for React 19.2 + TS strict + Vite (was Svelte chat UI) - devops skill: Vite dev server replaces Svelte; CI pipeline expanded to match the 7-stage pipeline (lint/format/typecheck/architecture/tests/frontend/security) - qa-engineer skill: LLM judge model reference replaced with the env-var seam (LLM_PROVIDER/LLM_API_KEY) the template ships - technical-writer skill: drop the take-home REPORT.md; map each docs/*.md to its purpose so the agent knows where to put what All six are still scoped to user-invocable: false (they auto-activate). Closes #16 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ure) (#9) (#39) Port .github/workflows/ci.yml from Teller. Bump python-version 3.12 -> 3.14 and node-version 20 -> 24. Pin all action references to commit SHAs (acceptance criterion). Make frontend-build / frontend-quality jobs guarded by `hashFiles('frontend/package.json') != ''` so they skip cleanly until #21. Coverage gate: pyproject.toml's [tool.coverage.report].fail_under stays at 75 (the eventual target). CI uses --cov-fail-under=0 until #17 + #18 land real source under src/; once those merge, drop the override and let CI honour the pyproject default. Drops the meta-gate jobs (branch-protection-sync, commit-type-sync) — those land in #10 with the .github/scripts/ they invoke. Closes #9 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The pinned SHA in #9 (e58605a9...) was the tag-object SHA, not the commit SHA. GitHub Actions does not auto-dereference annotated tags at workflow startup, so every run completed in ~0s with conclusion=failure and 0 jobs. Replace with d4b2f3b6... (the commit v5 points to). Update the bump-recipe comment to use `gh api .../commits/<tag>` which always returns the commit SHA whether the tag is lightweight or annotated. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the test-integration job entirely (no integration tests exist yet; will be re-added with #17+ once a real integration suite ships). Drop the per-step shell/continue-on-error overrides on the run blocks (defaults are correct). Drop the job-level defaults: run: working-directory: frontend on frontend-quality and inline `cd frontend &&` on each step (matches the frontend-build job style; simpler shape that is known-good). Add `-o addopts=` to the pytest unit-tests invocation so pyproject's `addopts` do not pull in coverage by default in this fast-feedback job (the coverage job is the one that enforces the gate). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
) Root cause of every "completed/failure with 0 jobs in 0s" run since #9 was `astral-sh/setup-uv@v5` — even with the commit-SHA dereferenced correctly, v5's pinned commit no longer satisfies GitHub Actions' validation. v8 (latest major, commit cec20831...) is the supported form. Now restores: lint, typecheck, test-unit, coverage, architecture, pre-commit, frontend-build (guarded by hashFiles('frontend/package.json')), frontend- quality (same guard). Drops test-integration — empty integration suite makes pytest exit 5 and there's no integration-marker test to land at this stage; add it back when a real integration test arrives. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the second half of #12 (release-drafter); pr-title.yml itself shipped in #10's bundle. Port .github/workflows/release-drafter.yml + the categories / autolabeler / version-resolver config in .github/release-drafter.yml verbatim from Teller. Pin release-drafter@v6 to commit SHA 6a93d829.... release-drafter is exempt from required-status-checks (workflow runs on push to main + PR label events; never on every PR). Already in EXEMPT_WORKFLOWS in check_required_contexts.py. Closes #12 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… (#53) Port .github/workflows/release.yml from Teller; bump python-version to 3.14, update setup-uv pin to v8 commit, checkout pin to v4 latest. Add a docker login + push pair so the built image lands at ghcr.io/<owner>/<repo>:<version> AND :latest (acceptance criterion: image must publish to GHCR). Compute the lowercase repo path via parameter expansion since GHCR rejects mixed-case path components. Permissions: contents:write + packages:write. SBOM pinned to cyclonedx-bom==7.3.0 in a uvx venv so the generator itself doesn't end up in the SBOM. Sanity-check the JSON before upload. Closes #13 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…odeQL (#14) (#54) The JSON specs (.github/branch-protection/{develop,main}.json + README.md) already shipped in #10. This PR adds the three remaining workflows that operate against them or alongside them: - branch-protection.yml — applies the JSON spec to main + develop on schedule (Monday 06:00 UTC), workflow_dispatch, and push to main when the spec or workflow itself changes. Requires a BRANCH_PROTECTION_TOKEN secret with admin:repo scope (default GITHUB_TOKEN cannot edit branch protection on the repo it runs in). Step summary diffs before/after each apply. - artifact-cleanup.yml — weekly artifact pruning (default 7 days, scheduled live, manual dry-run by default). Stops the account-wide artifact quota from accumulating. - codeql.yml — placeholder. workflow_dispatch only until the repo is public (or gains a GHAS subscription). All `on:` triggers commented in-file with the re-activation recipe. All four workflows are EXEMPT_WORKFLOWS in check_required_contexts.py (scheduled / dispatch-only / push-to-main-only); the meta-gate stays in sync at 12 required contexts. Closes #14 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add src/tools/registry.py: a generic dispatcher mapping tool name -> (input
schema, callable). Each tool's input + output are StrictModel subclasses.
Three-method API matches the issue spec:
- register(name, input_schema) -> decorator
- dispatch(name, raw_input) -> validates raw dict against input schema,
invokes the tool, returns typed output
- names() -> sorted list of registered tool names
UnknownToolError (KeyError subclass) raises on dispatch with a missing
name; Pydantic's ValidationError propagates on bad input (wrong type or
unknown keys via StrictModel's extra="forbid").
Module-global `registry` singleton; `echo_tool` (input/output pair
EchoToolInput/EchoToolOutput) self-registers at module load to demonstrate
the pattern.
Layer hygiene: registry.py imports only from src/models/. Verified by
lint-imports — both contracts still kept.
7 unit tests cover: module-global resolves echo, happy-path dispatch,
unknown-tool error, bad input rejection, unknown-key rejection, duplicate
registration, and registry isolation.
Closes #20
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#22, #23) (#59) Bundles two tickets that share the same frontend touch surface: #22 — typed SSE client primitive (frontend/src/lib/api/client.ts) - Port frontend/src/lib/api/client.js from Teller, rewritten as TS: generic over the parsed event shape (`SseEvent` interface), POST + body + AbortSignal supported, CRLF normalisation, malformed-chunk recovery (warns, doesn't throw). - Add typed SseError with optional status; createSession() and sendMessage<TEvent>(...) exports. - SseError uses an explicit field declaration instead of a parameter property — tsconfig's `erasableSyntaxOnly: true` rejects the latter. #23 — hello page + CSS palette + sample component test - Replace the Vite welcome screen with a real App.tsx that fetches /api/v1/health and renders `loading | ok | error` states with semantic ARIA roles + data-testids. - Port the Teller CSS-variable palette to frontend/src/styles/palette.css (light + dark via [data-theme='dark']); index.css imports it; App.css consumes the tokens (no raw hex). - Drop the Vite welcome assets (react.svg, vite.svg, hero.png, public/icons.svg). - frontend/src/App.test.tsx (Vitest + jsdom + Testing Library): mock fetch for the happy path (renders the ok badge with version) and the 500 path (renders the error message). Both PRs in one commit since the App page consumes the styles and lib shape; landing them separately would mean a half-shipped page in between. Closes #22 Closes #23 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…URITY, ARCHITECTURE + README, CONTRIBUTING, CLAUDE.md, CHANGELOG, TASKS.md (#25, #26) (#61) Closes #25 + #26 in one PR (the README references docs/* paths and TASKS.md references everything else; landing them separately would mean a half-broken docs tree in between). docs/* (all written for the template, not Teller-flavoured): - HARNESS.md — umbrella table mapping every layer to its config file and to the meta-gate(s) that catch drift in it. - INVARIANTS.md — five portable rules with numbered slots 6+ for project additions. - BOUNDARIES.md — ASCII layer diagram + the import-linter contract spec + how to add a layer cleanly. - DEVELOPMENT.md — prereqs, first-time setup, dev stack, justfile recipes table, branching diagram, commit-prefix table, CI workflow inventory, agent-hook setup, branch-protection token setup. - EVAL_HARNESS.md — runner architecture, three tolerance modes, wiring your agent / LLM client, adding a case, opt-in for nightly schedule. - SECURITY.md — threat model table + defence-in-depth ASCII map + container hardening notes + explicit out-of-scope list (auth, WAF, rate-limit, secret manager). - ARCHITECTURE.md — scaffold component diagram, request lifecycle, frontend lifecycle, slots that fill in as the project grows. Top-level docs: - README.md — what ships / quickstart / why-a-harness / docs index / versions table / license. - CONTRIBUTING.md — branching diagram, commit-prefix table, PR template callouts, "adding a check" recipe. - CLAUDE.md — agent project instructions: read-first list, workflow, code conventions, what-not-to-do, skills inventory. - CHANGELOG.md — release-drafter seed; first Unreleased entry summarises the harness extraction. - docs/TASKS.md — full ticket table with phase grouping + status emoji, matches the GitHub Project board. Closes #25 Closes #26 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First release PR — bringing every harness ticket (#1–#27 + #28's automated half) from
developontomain.After merge:
branch-protection.ymlis visible on the default branch, unblockinggh workflow run branch-protection.yml --ref main.release-drafterstarts drafting the v0.1.0 notes from the merged PRs.release.ymlis dormant until the firstv*.*.*tag.Verification
develophead (a16fca2).🤖 Generated with Claude Code