Skip to main content

Elenchus

CI PyPI Python 3.11+ License: MIT Docs

A standalone system for dialectical knowledge base construction, implementing the Elenchus protocol (Allen 2026) with a DuckDB material base backend.

The respondent develops a bilateral position [C : D] through natural language dialogue with an LLM opponent. Accepted tensions become material implications in a NMMS material base satisfying Containment.

Requirements

  • Python 3.11+
  • An LLM API key (Anthropic, OpenRouter, or any OpenAI-compatible provider)

Installation

pip install elenchus
export ELENCHUS_API_KEY=sk-ant-...    # or ANTHROPIC_API_KEY

For development:

git clone https://github.com/bradleypallen/elenchus-server.git
cd elenchus-server
pip install -e ".[dev]"

User Guide — full documentation covering concepts, the web interface, CLI, configuration, and a worked example.

Usage

First-time setup (multi-user mode)

Elenchus is a multi-user platform. Before the first sign-in you create an admin actor; everyone else joins by accepting an invite that admin issues.

# 1. Bootstrap the admin.
elenchus admin create --email admin@local --name "Admin"
# (prompts for a password, or reads ELENCHUS_ADMIN_PASSWORD)

# 2. Start the server.
elenchus

# 3. Open the browser and sign in as the admin.
# 4. In the admin dashboard, issue an invite to each user.
#    The dashboard renders the full ?token=... URL — share that link.
# 5. Users click the link, choose a display name and password, and land
#    in the app.

Upgrading from a single-user install? Run elenchus migrate-legacy once to register every existing ./dialectics/*.duckdb under the admin's account and relocate it into the per-actor directory layout. Idempotent.

Web interface

elenchus

Options: --port, --model, --api-key, --base-url, --protocol, --data-dir (see elenchus --help).

Open the URL shown in the terminal (default http://localhost:8741). The web interface provides:

  • Creating and resuming dialectics scoped to the current user
  • Natural language dialogue with the LLM opponent
  • Live bilateral state display [C : D]
  • Tension resolution (accept/contest)
  • Material implications accumulating in I
  • Derivability queries against the material base
  • An admin-only dashboard for issuing invites and managing users

Command line

# Interactive session (in-memory)
elenchus-cli --name "My Inquiry"

# Persistent session (saved to DuckDB file)
elenchus-cli --db my_inquiry.duckdb --name "My Inquiry"

# Resume a saved session
elenchus-cli --db my_inquiry.duckdb

API

All /api/sessions/* and /api/admin/* routes require an authenticated session. The flow is: POST to /api/auth/login to get a session cookie, then send subsequent requests with that cookie. A dialectic is addressed by the numeric session_id returned on create.

# 1. Log in (saves the cookie to ./cookies.txt).
curl -c cookies.txt -X POST http://localhost:8741/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "..."}'

# 2. Create a dialectic — the response includes "session_id" (e.g. 1).
curl -b cookies.txt -X POST http://localhost:8741/api/sessions \
  -H "Content-Type: application/json" \
  -d '{"name": "prov-o", "topic": "PROV-O Starting Point Terms"}'

# 3. Send a message.
curl -b cookies.txt -X POST http://localhost:8741/api/sessions/1/message \
  -H "Content-Type: application/json" \
  -d '{"message": "Entity is a thing with fixed aspects."}'

# 4. Get state.
curl -b cookies.txt http://localhost:8741/api/sessions/1

# 5. Accept a tension.
curl -b cookies.txt -X POST http://localhost:8741/api/sessions/1/tensions/1 \
  -H "Content-Type: application/json" \
  -d '{"action": "accept"}'

# 6. Check derivability.
curl -b cookies.txt -X POST http://localhost:8741/api/sessions/1/derive \
  -H "Content-Type: application/json" \
  -d '{"gamma": ["entity_fixed_aspects"], "delta": ["individuation"]}'

# 7. List your sessions (admins see every base in the platform).
curl -b cookies.txt http://localhost:8741/api/sessions

The legacy name-keyed routes (/api/dialectics/{name}/...) are retained as a compatibility alias — the study-participant flow still uses them — but new clients should use /api/sessions/{id}.

Admin-only routes: /api/admin/invites, /api/admin/users, /api/admin/users/{id}/{deactivate,reactivate}, /api/admin/backup, /api/admin/audit. Non-admins get a 403.

Architecture

src/elenchus/
├── server.py ──→ opponent.py ──→ LLM API (Anthropic / OpenAI-compatible)
│       ↓
│   dialectical_state.py
│       ↓
│   material_base.py
│       ↓
│   dialectics/*.duckdb
├── static/index.html
├── cli.py
└── pdf_report.py
  • server.py: FastAPI app serving the API and static frontend
  • opponent.py: LLM oracle — sends state to LLM API (Anthropic or OpenAI-compatible), parses structured responses, applies state transitions
  • dialectical_state.py: Definition 4 — S = ⟨[C : D], T, I⟩ backed by DuckDB
  • material_base.py: Definition 5 — B = ⟨L_B, |∼_B⟩ with pyNMMS-based derivability
  • dialectics/*.duckdb: Persistent state files (one per dialectic)

Persistence

The data directory ($ELENCHUS_DATA, default ./dialectics/) holds:

  • platform.duckdb — actors, auth sessions, invites, magic links, base ownership, platform settings. Held open by the server for its lifetime.
  • bases/{actor_id}/{base_name}.duckdb — one file per dialectic, owned by actor_id. Each file contains the atomic language L_B, all assessments (the base consequence relation |∼_B), the bilateral position [C : D], open and resolved tensions, and conversation history.
  • backups/elenchus-*.tar.gz — output of scripts/backup.py / POST /api/admin/backup (see Operations below).

Schema versions live in each file's meta.schema_version. The migration runner brings every file forward at open time; see src/elenchus/migrations/README.md for how to add a new migration.

Operations

Full deployment guide — systemd unit, Nginx + TLS, backup cron, log rotation, and a pre-pilot checklist — is in docs/OPERATIONS.md. See also the task-oriented guides on the documentation site: Administration (roles, dashboard, invites, users, cost, audit, backups, alerting), Running a Study (conditions, participant flow, questionnaires, blinded judging, export), and Deployment (local / production VM / cloud). Quick reference:

# Liveness + readiness probe (unauthenticated; for uptime monitors).
curl -sf http://localhost:8741/healthz
# {"status":"ok","schema_version":7,"phase_b_enabled":false,
#  "llm_configured":true,"checks":{"platform_db":"ok","data_dir":"ok"}}

# Audit drift between platform.duckdb and the filesystem.
elenchus audit

# Run a one-shot backup (everything → backups/elenchus-YYYYmmdd-HHMMSS.tar.gz).
# Server must be running; this hits POST /api/admin/backup.
python scripts/backup.py --email admin@local --password ...

# Cron entry (3 AM daily, keep latest 14 archives):
# 0 3 * * * ELENCHUS_BACKUP_EMAIL=admin@local ELENCHUS_BACKUP_PASSWORD=... \
#           python /opt/elenchus/scripts/backup.py >> /var/log/elenchus-backup.log 2>&1

# Agent-driven pilot simulation — robustness check before a live study.
# Drives researcher + participants (both conditions) + judges + export
# end-to-end against the real API. 'scripted' is free + deterministic
# (CI gate); 'llm' uses real personas for a pre-pilot dress rehearsal.
elenchus sim                       # 4 participants, 2 judges, scripted
elenchus sim --driver llm          # real LLM personas (needs an API key)

The simulation validates the platform (every role, every transition, blinding mechanics, cost, error handling under the real request stack) — not the science. LLM participants prove the machinery is robust; whether the two conditions produce different-quality outputs is what the human pilot measures.

# Per-persona MP4 walkthroughs — watch the system being used through
# the real UI, one video per perspective (participant in each
# condition, judge, researcher). Drives the served frontend in a
# headless browser; needs the [e2e] extra + a one-time chromium install.
pip install -e ".[e2e]" && python -m playwright install chromium
python scripts/record_demo.py --out demo-videos            # scripted (free)
python scripts/record_demo.py --driver llm                 # real dialogue
# Watch a dialectic unfold between two LLMs from a positum: a respondent
# (a domain expert defending a posited paragraph) vs the real Elenchus
# opponent. Prints the transcript + the resulting bilateral position
# [C : D], accepted material implications, and open tensions.
python scripts/run_dialectic.py                            # default sci-ontology positum
python scripts/run_dialectic.py --positum @paragraph.txt \
    --domain "the Gene Ontology" --turns 6 \
    --respondent-model claude-sonnet-4-6 --out dialectic.json

DuckDB is a single-writer-per-file store, so the production server runs as one process; horizontal scaling means migrating the platform DB to Postgres (the db/registry.py boundary is shaped to absorb that swap without touching route handlers). See design-notes/architecture-vision.md for the larger framing.

Configuration

Environment variables:

  • ELENCHUS_API_KEY: Required. Your LLM API key (also accepts ANTHROPIC_API_KEY).
  • ELENCHUS_MODEL: LLM model for the oracle (default: claude-opus-4-6)
  • ELENCHUS_BASE_URL: API base URL for OpenAI-compatible providers (e.g. https://openrouter.ai/api/v1)
  • ELENCHUS_PROTOCOL: API protocol — anthropic or openai (auto-detected from base URL)
  • ELENCHUS_DATA: Directory for .duckdb files (default: ./dialectics)
  • PORT: Server port (default: 8741)
  • SESSION_COOKIE_SECURE: Set to true in production behind HTTPS so the auth cookie carries the Secure flag.
  • BCRYPT_ROUNDS: bcrypt cost factor for password hashing (default 12). Tests override this to 4 to keep the suite fast — do not lower in production.
  • ELENCHUS_ENABLE_PHASE_B: opt-in flag for the theory-articulation speech acts (ASSERT_IMPLICATION, INTRODUCE_BEARER, RETRACT_IMPLICATION). Off by default: the live message route exposes only {COMMIT, DENY, ACCEPT_TENSION, CONTEST_TENSION, RETRACT, REFINE} to match the planned study's Elenchus-condition vocabulary. Set to 1/true outside study contexts.

Using OpenRouter

export ELENCHUS_API_KEY=sk-or-...
export ELENCHUS_BASE_URL=https://openrouter.ai/api/v1
export ELENCHUS_MODEL=anthropic/claude-opus-4-6
elenchus

Any OpenAI-compatible endpoint works the same way (Together, Groq, etc.).

Acknowledgements

This work was supported by a grant from the Alfred P. Sloan Foundation to the Alliance for Data Science and AI (G-2026-79650).

(Alfred P. Sloan Foundation · Alliance for Data Science and AI)

License

MIT — Copyright © 2026 University of Amsterdam. Author: Bradley P. Allen.

Release files for elenchus 0.4.1

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

Source distribution (sdist)

Source distribution for elenchus 0.4.1
File Size Uploaded
elenchus-0.4.1.tar.gz 453.0 kB Details

Built distribution (wheel)

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

Total release size: 705.7 kB

Release files / elenchus-0.4.1.tar.gz

Download URL elenchus-0.4.1.tar.gz
Size 453.0 kB
Tags Source
SHA-256 checksum
How to use checksums
82070f37ff4a5dc52bf73b50293d9d2ea3789ddccdc4a5a791c26e008fb3c4fa
BLAKE2b-256 checksum
How to use checksums
2178dca5cfb83fa486a96e77ece0d87c677d1461b45af73528f2ef2f4deef146
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 Sep 19, 2026.

Transparency log

Release files / elenchus-0.4.1-py3-none-any.whl

Download URL elenchus-0.4.1-py3-none-any.whl
Size 252.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f07bcfa8e9a1ccda2255c71314ae2cf91863122fddabc6dc98cf7fe6561e8df7
BLAKE2b-256 checksum
How to use checksums
c57e4c80bf1b1384962887f65d0f6892a85da39e2466fa504377bc16c3b97ec7
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 Sep 19, 2026.

Transparency log

Release history Release notifications | RSS feed

0.8.4

2 release files

0.8.3

2 release files

0.8.2

2 release files

0.8.1

2 release files

0.8.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.1 This release

2 release files

0.4.0

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

2 release files

0.1.1

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