Observed since 20 Oct, 17:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
abductio-core
ABDUCTIO MVP core engine
ABDUCTIO MVP core engine: deterministic scheduling, ledger updates, and a strict application boundary. You supply evaluator/decomposer/audit ports; the engine handles orchestration and invariant enforcement.
What ABDUCTIO does: Evaluates a MECE (mutually exclusive, collectively exhaustive) set of hypotheses about a question/phenomenon/case (the "scope") under credit constraints, with permutation-invariant scheduling and mandatory template-based decomposition to prevent asymmetric scrutiny.
Project status: core engine library. The HTTP API lives in abductio-service.
See architecture.md and docs/white_paper.org for the spec.
Requires Python 3.11+.
From PyPI:
pip install abductio-core
Optional OpenAI adapter dependency (used by abductio_core.adapters.openai_llm):
pip install abductio-core[e2e]
Local path install (for use inside another codebase):
pip install /path/to/abductio-core
Editable install for local development:
pip install -e /path/to/abductio-core
If you host this repo, you can also install directly from VCS:
pip install git+ssh://<your-host>/<org>/abductio-core.git
from dataclasses import dataclass, field
from typing import Any, Dict, List
from abductio_core import RootSpec, SessionConfig, SessionRequest, run_session
from abductio_core.application.ports import RunSessionDeps
from abductio_core.domain.audit import AuditEvent
@dataclass
class MemAudit:
events: List[AuditEvent] = field(default_factory=list)
def append(self, event: AuditEvent) -> None:
self.events.append(event)
@dataclass
class NoChildrenDecomposer:
def decompose(self, target_id: str) -> Dict[str, Any]:
if ":" in target_id:
return {"ok": True, "type": "AND", "coupling": 0.80, "children": []}
return {"ok": True, "feasibility_statement": f"{target_id} feasible"}
@dataclass
class SimpleEvaluator:
def evaluate(self, node_key: str) -> Dict[str, Any]:
return {"p": 0.8, "A": 1, "B": 1, "C": 1, "D": 1, "evidence_refs": "ref1"}
# Define the question/phenomenon you're evaluating (the "scope")
# and the competing hypotheses
request = SessionRequest(
scope="Germany's GDP trajectory in 2026", # What the hypotheses are about
roots=[
RootSpec("H_grow", "Economy will grow", "Not flat or shrink"),
RootSpec("H_flat", "Economy will be flat", "Not grow or shrink"),
RootSpec("H_shrink", "Economy will shrink", "Not grow or flat"),
],
config=SessionConfig(
tau=0.70,
epsilon=0.05,
gamma=0.20,
alpha=0.40,
beta=1.0,
W=3.0,
lambda_voi=0.10,
world_mode="open",
),
credits=10,
required_slots=[{"slot_key": "feasibility", "role": "NEC"}],
)
result = run_session(
request,
RunSessionDeps(
evaluator=SimpleEvaluator(),
decomposer=NoChildrenDecomposer(),
audit_sink=MemAudit(),
),
)
print(f"Ledger: {result.ledger}")
print(f"Stop reason: {result.stop_reason}")
The scope is the frame for the evaluation session. It's not itself a hypothesis - it's what the hypotheses are competing to explain or predict. This distinction is functional: it tells the engine what partition you're evaluating, enabling proper MECE accounting and H_other handling.
Given identical inputs (scope, hypotheses, evidence, credit budget), ABDUCTIO produces identical outputs regardless of:
This is achieved through canonical ordering (hash-based), frontier-only scheduling, and symmetric obligation templates.
Every hypothesis must be evaluated through the same template of required slots (default: feasibility, availability, fit, defeater_resistance). This prevents asymmetric scrutiny where one hypothesis gets loaded with requirements while rivals remain vague.
Public imports from abductio_core:
RootSpec, SessionConfig, SessionRequestSessionResult, StopReasonrun_session, replay_sessionPorts (implement in your app):
EvaluatorPort, DecomposerPort, AuditSinkPortRunSessionDepspip install -e ".[dev]"
pytest
Environment variables:
.env.example to .env and set OPENAI_API_KEY to run E2E tests that hit the OpenAI API.Narrative/source docs live in docs/ as Org/HTML/PDF assets. These are treated as
source material, not a hosted docs site.
Version is stored in pyproject.toml and tagged as vX.Y.Z on release. The
scripts/release.sh helper updates the version, commits, and tags.
Recommended: automated publish on tags via GitHub Actions + PyPI trusted publishing.
One-time setup (PyPI):
Promise-Foundation/abductio-core.github/workflows/publish.ymlRelease flow:
version in pyproject.tomlpytestgit tag vX.Y.Z && git push --tagsThe GitHub Action publishes the build to PyPI on tag push.
Helper script (recommended):
scripts/release.sh X.Y.Z
git push
git push --tags
Manual fallback:
python -m pip install --upgrade build twine
python -m build
twine upload dist/*
Token-based auth:
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=pypi-<your-token>
MIT. See LICENSE.
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
openaiEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | openai>=1.0 | runtime |
pydanticEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pydantic>=2.7 | runtime |
behaveEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | behave>=1.2.6; extra == "dev" | runtime |
ruffEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | ruff>=0.6.0; extra == "dev" | runtime |
mypyEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | mypy>=1.10.0; extra == "dev" | runtime |
pytestEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pytest>=7.0; extra == "dev" | runtime |
coverageEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | coverage>=7.0; extra == "dev" | runtime |
pytestEnvironment{
"extras": "",
"marker": "extra == \"e2e\"",
"requires_python": ">=3.11",
"evaluation": "NOT_EVALUATED"
} | pytest>=7.0; extra == "e2e" | runtime |
bdist_wheel · 31.81 KB · Python py3
sdist · 36.86 KB · Python source
Shared repository data · GitHub
Observed since 20 Oct, 17:18 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:e3ff64dc9118fa77a32b2a309a7d1dffd019f3fcd4dc300f3e648eb48833b618