wardhook-core
A LangGraph agent runtime with tool calling, retrieval with real source citations, and a one-command FastAPI server.
Part of Wardhook. Works completely on its own — it never imports the other Wardhook packages.
Install
pip install wardhook-core
# with a model provider
pip install "wardhook-core[anthropic]" # or [openai], [all]
Usage
from wardhook.core import AgentGraph, InMemoryVectorStore, Retriever, chunk_text
store = InMemoryVectorStore()
store.add(chunk_text(open("policy.md").read(), "policy.md"))
agent = AgentGraph(model="claude-opus-5", retriever=Retriever(store))
result = agent.invoke("What excess applies to storm damage?")
print(result["output"])
print(result["citations"][0]["source"]) # -> 'policy.md'
What you get
Provider-agnostic. AgentGraph accepts any object with .invoke(). Pass a
ChatAnthropic, a ChatOpenAI, or a test double. Nothing in the base install
depends on a provider SDK, so you are never locked in.
agent = AgentGraph(model=ChatOpenAI(model="gpt-4o")) # instance
agent = AgentGraph(model="anthropic:claude-opus-5") # name
agent = AgentGraph(model=my_fake) # test double, no API key
Tools from plain functions. The docstring becomes the description the model reads, so it is required rather than optional.
def lookup_claim(claim_id: str) -> str:
"""Look up the current status of a claim by its identifier."""
return db.claims.status(claim_id)
agent = AgentGraph(model="claude-opus-5", tools=[lookup_claim])
Citations are structural, not parsed. Retrieval returns records carrying source, chunk position and score. You render or verify them directly; the model cannot invent a citation for a document it was never shown.
for c in result["citations"]:
print(f"{c['source']} chunk {c['chunk_index']} (score {c['score']:.3f})")
RAG that runs with no API key. Document loading (PDF, Markdown, text), recursive chunking with overlap, and a NumPy vector store. The default embeddings are a classical hashing vectoriser — no model weights, no network — so the pipeline works the moment you install it. Swap in real embeddings for production; the interface is identical.
store = InMemoryVectorStore(embeddings=OpenAIEmbeddings())
store.save("index") # index.npz + index.json
store = InMemoryVectorStore.load("index", embeddings=OpenAIEmbeddings())
Serve it in one command.
wardhook serve myapp.agents:support_agent --port 8000
Exposes POST /invoke, GET /health, GET /info, and OpenAPI docs at /docs.
A production Dockerfile ships with the package.
Composing with the rest of Wardhook
AgentGraph takes guardrails=[...] and telemetry=True, but core does not
depend on the packages that provide them. Both attach through structural
contracts in wardhook.core.protocols, so any object of the right shape
works — from Wardhook, from your codebase, or from somewhere else entirely.
from wardhook.core import AgentGraph
from wardhook.guardrails import PIIRedactor, RoleBasedToolPolicy # optional install
agent = AgentGraph(
model="claude-opus-5",
tools=[lookup_claim],
guardrails=[PIIRedactor(pack="insurance"), RoleBasedToolPolicy(...)],
telemetry=True, # requires wardhook-observability
)
Writing your own takes no dependency at all:
class NoInternalCodenames:
name = "no-codenames"
def on_output(self, text, context):
if "PROJECT_HALCYON" in text:
return {
"action": "redact",
"text": text.replace("PROJECT_HALCYON", "[internal]"),
"reason": "internal codename",
"rule": "codename-list",
}
return {"action": "allow"}
agent = AgentGraph(model="claude-opus-5", guardrails=[NoInternalCodenames()])
The full contract is three optional hooks — on_input, on_output,
on_tool_call — each returning something with an action of "allow",
"redact" or "block". Implement only the ones you need.
Notes
- Guardrails fail closed. If a guardrail raises, the run is blocked and the
failure is recorded. Set
guardrail_error_policy="allow"or"raise"to change that. - Denied tool calls never execute. The model is told it was denied through a normal tool result, so it can recover instead of failing the run.
- Tool errors go back to the model, not to your caller — an agent that can see a failure can often work around it.
Links
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wardhook_core-0.1.1.tar.gz.
File metadata
- Download URL: wardhook_core-0.1.1.tar.gz
- Upload date:
- Size: 56.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
54f953502c16d4a81e584a8206b554e8b59cdb165dd319c47e11718a8ee9c9eb
|
|
| MD5 |
50c86d84c84186b8325c9bfe2fe53cff
|
|
| BLAKE2b-256 |
3d2161c0861e80d8591f5c72ee50ffa58e43162ffe48458b37f457151f3786d4
|
Provenance
The following attestation bundles were made for wardhook_core-0.1.1.tar.gz:
Publisher:
release.yml on justicebajaj161/wardhook
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wardhook_core-0.1.1.tar.gz -
Subject digest:
54f953502c16d4a81e584a8206b554e8b59cdb165dd319c47e11718a8ee9c9eb - Sigstore transparency entry: 2620835521
- Sigstore integration time:
-
Permalink:
justicebajaj161/wardhook@707c5f985499cdb1c8f2035b362c9df4343bfa65 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/justicebajaj161
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@707c5f985499cdb1c8f2035b362c9df4343bfa65 -
Trigger Event:
push
-
Statement type:
File details
Details for the file wardhook_core-0.1.1-py3-none-any.whl.
File metadata
- Download URL: wardhook_core-0.1.1-py3-none-any.whl
- Upload date:
- Size: 47.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c47712b9e7c0eb58626dbd4f09c12f694aac6719620e814d5319d8d522dfca5a
|
|
| MD5 |
1275a17fa8f7376f42e4aad6a1e35fe2
|
|
| BLAKE2b-256 |
43824bce4b490aa9852e5e9d2508e160fe347254c987b8b0a85c2d574d436ceb
|
Provenance
The following attestation bundles were made for wardhook_core-0.1.1-py3-none-any.whl:
Publisher:
release.yml on justicebajaj161/wardhook
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wardhook_core-0.1.1-py3-none-any.whl -
Subject digest:
c47712b9e7c0eb58626dbd4f09c12f694aac6719620e814d5319d8d522dfca5a - Sigstore transparency entry: 2620835532
- Sigstore integration time:
-
Permalink:
justicebajaj161/wardhook@707c5f985499cdb1c8f2035b362c9df4343bfa65 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/justicebajaj161
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@707c5f985499cdb1c8f2035b362c9df4343bfa65 -
Trigger Event:
push
-
Statement type: