symbolic-reasoning
Policy-adherent, auditable reasoning for AI agents.
Research preview.
symbolic-reasoningis pre-1.0 and under active development. The API, the.srglanguage and output formats may change between minor releases without deprecation. Review its outputs before relying on them for consequential decisions. Provided "as is", without warranty, under the Apache 2.0 License.
symbolic-reasoning evaluates policies deterministically. You write a policy in the .srg language; the library works out which questions need answering, asks your oracle (an LLM, a database, a human), and returns the outcomes with a reasoning trace.
| Concern | Handled by |
|---|---|
| What are the rules? | Your policy (.srg) |
| What is true in this case? | Your oracle |
| Which question or decision follows? | The runtime |
| Why was that decision made? | The reasoning trace |
Installation
Requires Python 3.12+.
uv add symbolic-reasoning # or: pip install symbolic-reasoning
Quick start
Save a policy as loan_approval.srg:
predicate has_good_credit: "Does the applicant have a credit score of 700 or above?"
predicate has_stable_income: "Does the applicant have stable employment for at least 2 years?"
predicate has_low_dti: "Is the applicant's debt-to-income ratio below 43%?"
predicate has_down_payment: "Has the applicant provided at least 20% down payment?"
outcome approved: "Loan Approved"
outcome denied: "Loan Denied"
outcome manual_review: "Sent to Manual Review"
define core_eligible: all(has_good_credit, has_stable_income, has_low_dti)
path approve: all(core_eligible, has_down_payment) => approved
path review: all(core_eligible, not(has_down_payment)) => manual_review
path deny: not(core_eligible) => denied
Solve it with an oracle. This one asks you at the terminal:
import asyncio
import symbolic_reasoning as sr
async def oracle(request: sr.OracleRequest) -> dict[str, sr.Answer]:
answers = {}
for predicate_request in request.predicate_requests:
p = predicate_request.predicate
reply = input(f"{p.question} (y/n): ")
answers[p.id] = sr.Answer(is_met=reply == "y", reasoning=f"User answered {reply}")
return answers
async def main() -> None:
srg = sr.compile_srg_file("loan_approval.srg")
execution = await sr.asolve(srg, oracle)
for path in sr.reasoning_trace(execution).outcome_paths:
print(srg.outcomes[path.outcome_id].description)
for step in path.steps:
mark = "YES" if step.is_met else "NO "
print(f" {mark} {srg.predicates[step.predicate_id].question}")
asyncio.run(main())
It prints each outcome reached and the answers that led to it:
Sent to Manual Review
YES Does the applicant have a credit score of 700 or above?
YES Does the applicant have stable employment for at least 2 years?
YES Is the applicant's debt-to-income ratio below 43%?
NO Has the applicant provided at least 20% down payment?
Learn more
- The SRG language: the
.srgsyntax, how policies are evaluated and how to design them. - Python guide: oracles, step-by-step solving, coverage, reasoning traces, recording and replay, and the API reference.
Use with agents
The quick start runs a policy as a workflow: your code drives the solve and calls the oracle for each round of questions. The agent tools invert that control. The agent drives the solve through tool calls, starting an execution, answering each question from the case evidence and reading the outcomes, while the library still decides which questions are asked and how the answers combine.
Serve the tools over MCP with the mcp extra:
uv add "symbolic-reasoning[mcp]"
uv run python -m symbolic_reasoning.mcp --srg loan_approval loan_approval.srg
The server talks over stdio, so a host such as Claude Code launches it. See MCP setup to connect one.
To use the tools without MCP, see the Python guide.
Use with decision models
Every predicate is a yes/no question about the case, which is what a decision model answers. Use one as the oracle: the policy fixes which questions are asked and how their answers combine, and the model answers each from the case evidence. Map its probability to is_met and keep the probability in reasoning, so the trace shows how confident each answer was.
The Jev example does this with TypeSafe's Jev.
Examples
examples/integrations/jev: an oracle backed by the Jev decision model, which answers a policy's questions from Markdown case files and records the run.examples/data: an underwriting policy with an application, and a medical necessity review policy with a synthetic clinical record and a replay.
Metadata
Release files for symbolic-reasoning 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| symbolic_reasoning-0.7.0.tar.gz | 88.2 kB | Without provenance | Details for symbolic_reasoning-0.7.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| symbolic_reasoning-0.7.0-py3-none-any.whl | Python 3 | none | any | Details for symbolic_reasoning-0.7.0-py3-none-any.whl |
Total release size: 185.4 kB
Release files / symbolic_reasoning-0.7.0.tar.gz
| Download URL | symbolic_reasoning-0.7.0.tar.gz |
|---|---|
| Size | 88.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
920ced0fcd96a2466694cd354f321ad52b84cb9178853fdfaa09f8dc646119ea
|
|
BLAKE2b-256 checksum How to use checksums |
b0b22662da4c407e1f6da33ff1ec1c038436250d3734816b37698503a0b77b9d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / symbolic_reasoning-0.7.0-py3-none-any.whl
| Download URL | symbolic_reasoning-0.7.0-py3-none-any.whl |
|---|---|
| Size | 97.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bbfb0fd0122b482314e326e4eab7c3b6bea9c7adb3babb12410ef7be41dd4be0
|
|
BLAKE2b-256 checksum How to use checksums |
5bbffaea4845b9d46a2d07b5b6dd587d0829b3d31edad4d3dc1923d1dceb672b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for symbolic-reasoning 0.7.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.