Conversation
An independent implementation of the ACS v0.1.0 wire contract under reference-implementations/agt-python/: JSON-RPC envelopes, handshake negotiation, the hook taxonomy, the five dispositions, the SessionContext chain with a published chain_hash, replay and skew protection, and the HMAC-SHA256 baseline signature. Wrapped MCP is not implemented yet, so the ServerHello answers profiles_accepted: [] rather than claiming acs-core; the README's status table says exactly which parts are implemented. The suite validates envelopes against this repository's schemas by relative path, pins the cross-implementation signature vectors from the open Go port (GenAI-Security-Project#169), ports the conformance harness's ten external probes, and pins every hook's schema to its method name. A path-scoped workflow runs it in CI. Signed-off-by: Duke - Duc Dinh <dtduc.contact@gmail.com>
protocols/MCP/* and the explicit-version wrapped:mcp-<version>/* form now route to an MCP handler that reads the wrapped JSON-RPC 2.0 message (a request or the response it answers), checks it, and hands it to the policy engine intact; a malformed message is INVALID_PARAMS. A wrapped method is negotiated only when the ClientHello declares the protocol in wrapped_protocols, and the explicit-version form only at a declared version. The method table now carries hooks.md's per-hook permitted dispositions: a disposition a hook cannot carry is substituted (DENY where the hook permits it, ALLOW with a reason at audit-only hooks and postCompact), including on every Guardian-authored denial, so no DENY is ever sent at a hook that permits none. Decisions are validated against modifications.json, ask-details.json, and defer-details.json, plus §6.3's disjoint-target rule with the wrapped call's own parameter-override pointer. steps/sessionEnd closes the session (a later step is answered with a session_closed denial, replay history survives), a key_id or agent_id other than the session's is answered with a signed denial rather than an error, and an undefined method is METHOD_NOT_FOUND while agbom/* stays CAPABILITY_NOT_NEGOTIATED. The handshake now enforces the timestamp skew like any request, responses are signed under the deployment's key_id throughout, the transport refuses a missing or malformed Content-Length and closes cleanly, and the TypeScript workflow's path filter is narrowed to its own tree so a Python-only change does not pay for a Bun install. Signed-off-by: Duke - Duc Dinh <dtduc.contact@gmail.com>
One recv() is not the whole response: http.server flushes headers and body as two writes, and Linux split them across segments, so the tests failed on CI while passing on macOS. The loop ending is itself the proof the server closed the connection. Signed-off-by: Duke - Duc Dinh <dtduc.contact@gmail.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Adds a Python reference Guardian implementation under
reference-implementations/agt-python/: the ACS-Core wire contract(JSON-RPC envelopes, handshake negotiation, the 19 hooks, wrapped MCP, the
five dispositions, the SessionContext chain with a published
chain_hash,replay and skew protection, the HMAC-SHA256 baseline signature), a policy
engine interface with a small built-in engine, and a test suite that validates
envelopes against this repository's schemas by relative path.
Which issue does this implement
Closes #86
meaning, so it needs no issue
Base branch
integration, because this touches the specification, schemas, a referenceimplementation, an adapter, tests, or CI
main, because every changed path is on the documentation lane allowlist inCONTRIBUTING.md
Type of change
I tested this
uv run pytest -vpasses on my machine (110 tests, fromreference-implementations/agt-python/)uv run mkdocs build --strictpasses on my machineChecklist
git commit -s(required by the DCO)Security
Coordination
I posted on #78 on 2026-09-22 asking whether that sample is still active, and
flagged the structural question (
samples/vsreference-implementations/)to @rocklambros; no reply yet at the time of opening. This is a draft until
the workstream decides where Python lives. It currently follows the
agt-goprecedent underreference-implementations/agt-python/. It builds on#78's FastMCP instrumentation idea rather than duplicating it — a host adapter
is not in this PR.
What it implements, and what it does not
Every ACS-Core item in
docs/spec/conformance.mdis implemented, so theServerHello accepts
acs-core. Not claimed:acs-trace,acs-inspect,acs-provenance,acs-crypto,acs-audit;agbom/*is refused with-32003; Intent/IBAC is not implemented (Intent is optional andIBAC-conditional, and
ask_detailspasses through).README.mdcarries theper-item status table naming the tests that cover each row.
Evidence
ported (
tests/test_external_probes.py), nine of them signature-verified;the external mode itself is contributed in Add a Go Guardian reference implementation #169, which is not merged, so
this port is the local gate until it lands.
in
tests/testdata/README.md, and pinned byte for byte.specification/v0.1.0/by relative path, soa schema change fails the suite.
.github/workflows/reference-implementation-python.ymlis path-scopedto this tree; the existing TypeScript workflow's path filter is narrowed to
its own tree so a Python-only change does not pay for a Bun install.
One spec inconsistency this PR works around
The examples in
docs/spec/instrument/extend_mcp.mdplace the wrapped MCPmessage directly in the ACS envelope's
params— a shaperequest-envelope.jsonrejects (paramsrequiresacs_version,request_id,timestamp,metadata, andpayload). This tree follows theschema (the MCP message is carried intact in
params.payload), as the Go portin #169 does, and says so in its README. Worth an upstream issue if you agree.