Skip to main content

assessment-lens

Part of the lens family.

Python 3.11+ License: MIT

Signals-based assessment. Analysers generate signals about student submissions; this lens maps those signals to a rubric as observations, not grades. A lecturer reads the observations, weighs them, and assigns the mark. The AI narrates and cites; it never scores. A human stays in the loop.

assessment-lens is a lens (an assessment-aware product), not an -analyser. Analysers are assessment-agnostic signal generators; lenses sit above them. It consumes analysers (via bundle-analyser); it never generates signals. See ADR-0001.

Why "observations, not grades"

LLMs are inconsistent at the precise act of marking. So the lens keeps them off it. The deterministic signals (from analysers) are the anchor; an Observation maps a signal or two to a rubric Criterion with cited evidence, a short narration bound to that evidence, and a coverage (present / partial / absent) — which is "is the evidence there?", derived from thresholds, not a mark. There is deliberately no score/mark/weight field anywhere in the model.

Pipeline

Specification ──draft-rubric (LLM, reviewed)──▶ Rubric (criteria + mapping) + deliverables  [YAML]
Submissions root ──discover──▶ one Submission per subfolder
each Submission folder ──bundle-analyser──▶ Signals
Signals + Criteria + Deliverables ──alignment-check──▶ Observations
                                                         └─▶ cohort triage sheet + per-student reports
lecturer reads observations → assigns marks → writes feedback

assess is folder-dumb: one rubric + one folder of submission subfolders. Group/individual splits and mark-combining are handled outside (pre/post) or by running assess per folder.

Three commands

  • assess — structured rubric + a submissions folder → observations (cohort sheet + per-student reports). Add --llm for evidence-bound narration on each observation (opt-in; needs the [llm] extra + a provider — ANTHROPIC_API_KEY by default, or a local Ollama via ASSESSMENT_LENS_PROVIDER=ollama).
  • draft-rubric — free-form specification → a proposed structured rubric for the lecturer to review/edit before use. LLM-assisted; reads text/markdown directly and .pdf/.docx/.pptx via the [documents] extra.
  • serve — opt-in HTTP API ([serve] extra) so a desktop shell / UI can drive the lens: same /health + /manifest contract as the analysers, role: lens. Binds to 127.0.0.1; set ASSESSMENT_LENS_AUTH_TOKEN to require a bearer token on the assessment routes.

Install

# from PyPI
pip install assessment-lens

# from source (family layout)
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"

# pull the whole analyser stack into the same env (for `assess` to run for real):
uv pip install -e ".[dev,analysers]"

# opt-in LLM features (narration + draft-rubric):
uv pip install -e ".[llm]"     # + export ANTHROPIC_API_KEY=...

assess shells out to the bundle-analyser CLI (it must be on PATH). The [analysers] extra installs it; or point assessment-lens at an environment where it is already installed.

Quick start

# 1. author a structured rubric (or start from the example)
cp examples/data-viz-rubric.yaml my-rubric.yaml

# 2. lay out submissions: one subfolder per student/group
#    submissions/alice/{report.pdf,demo.mp4}  submissions/bob/...

# 3. assess (add --llm for narrated observations)
assessment-lens assess my-rubric.yaml submissions/ -o out/
#    -> out/cohort-sheet.csv         (row per submission × criterion, sortable)
#    -> out/reports/<id>.md          (per-student observation sheet, no marks)

# or draft a rubric from a free-form spec, then review/edit it
assessment-lens draft-rubric assignment-brief.md -o my-rubric.yaml

Submissions are analysed sequentially (one bundle-analyser run each), so budget accordingly for large cohorts — e.g. 300 submissions × 30 s ≈ 2.5 h. A submission that fails to analyse is recorded as an error row in the cohort sheet and never aborts the run; re-run just that one with --only <id> once fixed.

Rubric schema (the central contract)

assignment: "Data-Viz Project"
component: individual                 # plain label; assess ignores it
expected_deliverables:
  - id: report
    description: "Written report (~2000 words)"
    accepts: [document]               # content kinds that satisfy it
  - id: demo
    description: "≤5-min recorded demo"
    accepts: [video]
rubric:
  - id: critical-thinking
    description: "Evidence of critical engagement / analysis"
    signals_of_interest: [conversation.critical_thinking, reflection.depth]  # OPTIONAL mapping

signals_of_interest is the signal→criterion mapping, and it's optional. Pinned → deterministic coverage. Blank → alignment-check selects signals at runtime and shows its choice (near-term).

Status

v0.5. Working today:

  • ✅ Rubric load/validate; deliverable reconciliation; submission discovery
  • ✅ assess orchestration + evidence-bound observations + threshold coverage; per-submission fault isolation (one failure never aborts the cohort)
  • ✅ cohort sheet (CSV, spreadsheet-injection-safe) + per-student reports (Markdown)
  • ✅ bundle-analyser integration — verified against the real CLI output schema
  • ✅ LLM narration (assess --llm) — narrate-and-cite, bound to evidence; degrades to empty notes when the [llm] extra/key is missing
  • ✅ multi-provider LLM — Anthropic by default; local Ollama or any OpenAI-compatible endpoint via ASSESSMENT_LENS_PROVIDER
  • ✅ draft-rubric — proposes a rubric from a free-form spec (always review before use)
  • ✅ cohort-relative distinctiveness ([distinctiveness] extra) — three comparison spaces; neutral, never a verdict
  • ✅ serve ([serve] extra) — HTTP face for the desktop shell, optional bearer-token auth via ASSESSMENT_LENS_AUTH_TOKEN
  • 📋 Runtime signal selection when signals_of_interest is blank — deferred

Development

ruff format . && ruff check . && pytest -v

License

MIT — see LICENSE.

Metadata

Release files for assessment-lens 0.5.2

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

Source distribution (sdist)

Source distribution for assessment-lens 0.5.2
File Size Uploaded
assessment_lens-0.5.2.tar.gz 188.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for assessment-lens 0.5.2
File Interpreter ABI Platform
assessment_lens-0.5.2-py3-none-any.whl Python 3 none any Details

Total release size: 222.7 kB

Release files / assessment_lens-0.5.2.tar.gz

Download URL assessment_lens-0.5.2.tar.gz
Size 188.2 kB
Tags Source
SHA-256 checksum
How to use checksums
902638f3a93edb6a2f44a52aa2eb663f7ee004254f80c5d5e80a16d468b638c3
BLAKE2b-256 checksum
How to use checksums
14835e800a7aa05f0d0bca43726b6db852de9ca3fc927c5de46c700f557d2169
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.0

Release files / assessment_lens-0.5.2-py3-none-any.whl

Download URL assessment_lens-0.5.2-py3-none-any.whl
Size 34.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b9b1744b8e2e303ad2e8db1eb8a4a4a42fbd0a0c10d9078f8d1b6e3c4cb72937
BLAKE2b-256 checksum
How to use checksums
b505768501e0d3e8cd07d96e1f0ceffe586931ae545526a75b95f56fc0d080eb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.0

Release history Release notifications | RSS feed

This release

0.5.2 This release

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.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