Skip to main content

codepraxis

Build real-world coding assessments from your own repository.

pip install codepraxis

codepraxis example                    # see a real question, no account needed
codepraxis login
codepraxis install claude-plugin      # design and build questions with Claude
codepraxis                            # where am I, what is next
codepraxis guide                      # the whole thing explained

What this is

CodePraxis gives candidates real engineering work instead of algorithm puzzles. They open a browser, land in a real editor in a real container, and fix or build something. Hidden tests decide whether it worked.

This CLI is how you make those questions — keeping them in your own git repository, editing them with your own tools, and checking them before they reach anyone.

A question is a directory: starter code, a test module, instructions.

The steps

plan  →  build  →  try  →  ship
plan Talk it through, agree what to test. No code yet.
build Claude writes the question, tests it, and fixes what fails.
try Open it exactly as a candidate would. Nothing published.
ship Publish as a draft, then go live.
edit Pull one back down to change it later.

Run codepraxis at any point to see where you are and what to type next.

Working with Claude Code

codepraxis install claude-plugin

Writes a local plugin into .codepraxis/claude-plugin/, then prints the two commands that enable it. You get:

  • /codepraxis:plan — design a question: what it tests, what the candidate starts from, the cases, how long it should take
  • /codepraxis:build — write it, run it, repair what fails
  • /codepraxis:validate — check an existing question and fix it
  • a pack-authoring skill that loads automatically when Claude touches a question, so it already knows the contract

Re-run with --force to overwrite an existing install.

Planning refuses to proceed on a question a model can solve from the brief alone. Candidates have an AI agent in the container, so a question that is one prompt away from done measures nothing.

Doing it by hand

The CLI works without Claude:

codepraxis new my-question                 # scaffold one that already passes
codepraxis lint my-question                # static checks, no execution
codepraxis validate my-question            # run it, fast and advisory
codepraxis ship my-question                # validates in the runner, then publishes
codepraxis list                            # your company's questions
codepraxis edit 214 --open                 # update details, open a preview
codepraxis ship my-question --challenge-id 214   # publish an edit, not a duplicate

Two kinds of checking

Command Runs Speed Counts?
codepraxis lint Static rules over the files milliseconds Advisory
codepraxis validate --local Pure-Python harness on your machine seconds No — advisory
codepraxis validate --remote The real runner image, on CodePraxis ~1 min Yes — gates publish

lint never imports your code, so it is safe on a question you did not write and fast enough for every save.

--local reproduces how the runner loads, orders and scores a question, so it catches most mistakes in the inner loop. It is not the container: it does not run setup.sh and does not have the image's package set. Anything it cannot check is reported as a note rather than silently passing. Publishing always requires a remote run.

The rule that matters most

Every question is validated twice:

  • solution — source/ overlaid with solution/. Must pass everything.
  • starter — source/ alone. Must fail.

The starter run is the one authors forget. A question whose starter already passes has tests that do not discriminate, and every candidate scores full marks.

webhook-debug  (local)
  solution  18/18 passed
  starter   0/18 passed
  PASSED  8.9s

Three verdicts: PASSED, FAILED, and INCONCLUSIVE (this tier lacked the infrastructure to judge it — not a failure, and it does not fail the command). --json always emits a single document with a packs array.

Questions that call a model

By default there is no model endpoint locally, so cases that need one are reported unverifiable rather than failed — a question is not broken just because your laptop has no LLM proxy. Point it at a real endpoint and they run for real:

export OPENAI_API_KEY=...              # or --llm-api-key
export OPENAI_BASE_URL=...             # or --llm-base-url
codepraxis validate my-question

Once a key is configured the leniency stops: a model failure is then a real failure, because it can be judged.

Layout

challenges/my-question/
├── spec.md                  the plan — what this tests and why
├── publish.json             title, difficulty, time limit, tech stack
├── metadata.json            {"name": "..."} — becomes the workspace directory
├── backend.conf             {"BACKEND": "AI", "LANGUAGE": "PYTHON"}
├── setup.sh                 optional; installs dependencies (remote only)
├── source/                  what the candidate starts from
├── ._tests/test_1.py        a `testCases` class
└── ._course_data/
    ├── course_toc.json      selects the active test module
    └── feature.md           the Instructions tab
solution/                    sibling, never uploaded — the reference solution

setup.sh runs on every container load, not once at build time. Pin your versions: an unpinned install resolves to whatever is current that day, and a breaking release later fails during a candidate's assessment.

Authentication

codepraxis login

Prompts for an API key (hidden input), verifies it, and stores it at ~/.config/codepraxis/config.json with 0600 permissions. It prints which company the key publishes as — worth reading, because that is what every publish is scoped to.

In CI, skip the prompt:

export CODEPRAXIS_TOKEN=...
export CODEPRAXIS_API_URL=...        # optional; defaults to the production API

Publishing

codepraxis ship my-question            # draft, with confirmation
codepraxis ship my-question --live     # straight to candidates
codepraxis ship my-question --yes      # non-interactive, for CI

Publishing is deliberately strict, because a published question can be assigned to candidates immediately:

  • Remote validation runs first. Local results never qualify. Reuse an earlier passing run with --validation-run-id.
  • A reference solution is required. It is what proves the question is solvable.
  • It publishes as a draft unless you pass --live.
  • The company comes from your API key. The CLI never sends a company id — ownership is derived server-side, so a compromised or mistyped client cannot publish into someone else's catalog.

Publishing an edit

Changing the content of a question means re-publishing it. Pass the id, or you get a second copy:

codepraxis ship my-question --challenge-id 214

With --challenge-id the platform adds a new version and keeps the question's id, assignments and history.

Deleting

codepraxis delete 214

Asks first, and the platform refuses once the question has been assigned to anyone — deleting it then would orphan attempts and reports. To take an assigned question out of circulation, set it back to draft with codepraxis edit 214 --status draft.

Older command forms

--publish, --list, --edit, --delete, --login, --install and --example still work. They are hidden from help and print a pointer to the subcommand that replaced them.

Development

python3.11 -m pip install -e '.[dev]'
pytest
ruff check src tests scripts

The package has no runtime dependencies. The harness must run on an author's machine with nothing but a Python interpreter, so keep it that way — the remote tier uses urllib from the standard library for the same reason.

See ARCHITECTURE.md for how the pieces fit together.

Conformance tests

The harness mirrors the production runner's behaviour (setupCodeBase.py, koro/test_loader.py, koro/test_runner.py). Mirrors drift, so tests/conformance/ replays the harness across a corpus of real questions and asserts the expected verdicts.

That corpus is private and lives outside this repository:

PRAXIS_CONFORMANCE_PACKS=/path/to/question-bank pytest tests/conformance

Without the variable the conformance tests skip.

Do not vendor questions into this repository. This package is published publicly. No challenge content, no reference solutions, no fixtures derived from real questions. Scaffold templates must be written from scratch.

Release files for codepraxis 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for codepraxis 0.4.0
File Size Uploaded
codepraxis-0.4.0.tar.gz 70.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for codepraxis 0.4.0
File Interpreter ABI Platform
codepraxis-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 148.2 kB

Release files / codepraxis-0.4.0.tar.gz

Download URL codepraxis-0.4.0.tar.gz
Size 70.0 kB
Tags Source
SHA-256 checksum
How to use checksums
efa4f8a8630bace69a67408d61bcafbc772d8793fa462861b331397f5500f4c4
BLAKE2b-256 checksum
How to use checksums
0542f513f4feb16fad0cf57f941b9ff1f0e9d278ef516b8e21f5589567499e16
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release files / codepraxis-0.4.0-py3-none-any.whl

Download URL codepraxis-0.4.0-py3-none-any.whl
Size 78.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cfb580d814e8ed26686fe7b3b2f489e6b949b65aec876f4ec632e86d53ab5dc9
BLAKE2b-256 checksum
How to use checksums
7061cc197601d88f7078cf315b65db6c8034c59f4004727654ad9eb66a56f5c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 11, 2026.

Transparency log

Release history Release notifications | RSS feed

1.0.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

This release

0.4.0 This release

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page