Skip to content

Split the shared module into acs.core and acs.client - #477

Closed
bar-capsule wants to merge 1 commit into
refimpl/adapters-01-package-layoutfrom
refimpl/adapters-02-core-client
Closed

bar-capsule wants to merge 1 commit into
refimpl/adapters-01-package-layoutfrom
refimpl/adapters-02-core-client

Conversation

@bar-capsule

@bar-capsule bar-capsule commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #476. Next: #478. The full stack is listed in #22.

What changed

  • acs.core holds the protocol logic that does no I/O: RFC 8785, HKDF, signing and verifying with a given key, decision rules and MODIFY composition, error codes, response binding, IDs and timestamps. acs.client holds what reads configuration or touches the network or disk: the secret, URL checks, the handshake and its cache, session state, audit records. Each package lists its public API in __all__, and core imports nothing outside core.
  • The destructive-command scan moves into the example Guardian, next to its pattern set. The do_handshake and _signing_secret aliases and the unused install_path_for_sibling are deleted.

Ariel's findings this answers

Where this differs from Ariel's proposal

  • The destructive-command scan moves into the example Guardian, next to its patterns, rather than to examples/destructive_bash.py, which arrives with the Guardian split.

Which issue does this implement

Part of #134

Base branch

Stacked on #476, not on integration. It lands through #22; see the stack in #22.

Type of change

  • Reference implementation or adapter

I tested this

At this slice's top (c5c64d65), with claude removed from PATH and ACS_LIVE_CLAUDE and ACS_SPEC_DIR unset: 313 passed and 3 expected skips with the NAT extra, 275 passed and 3 expected skips without it. The skips are the two opt-in live Claude Code tests and the manual Cursor procedure. CI passes on this PR, including the installed-wheel check on Python 3.11 and 3.12.

Checklist

  • Commits are signed off with git commit -s (required by the DCO)
  • Prose follows STYLE.md
  • No secrets, tokens, or internal URLs in the diff

Security

Unchanged; the code moves verbatim.

acs.core holds the protocol logic with no I/O; acs.client holds
configuration, network, disk and audit. The code moves verbatim and
behavior is unchanged.

Signed-off-by: Bar Kaduri <bar@capsule.security>

@drk-ram drk-ram left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at head c5c64d65ea8a02b64ababd123d28f4a68c77d886.

I did a function-by-function diff against the pre-split acs/_common.py (979 lines) to make sure nothing silently disappeared in the split. Everything is accounted for:

  • All 29 top-level defs/classes from the old module land in either acs.core (no I/O: _canonical, _decision, _envelope, _errors, _handshake (just method_evaluated), _signing) or acs.client (I/O: _audit, _handshake (the actual handshake + its disk cache), _secrets, _signing, _store, _transport, _urls), with each package listing its surface in __all__ and core importing nothing from client.
  • scan_destructive_bash_safely and DESTRUCTIVE_SCAN_MAX_LEN correctly move into src/acs/guardian/example_guardian.py rather than either core or client - it's policy-specific to the teaching Guardian and calls audit_event, so it doesn't belong in the no-I/O core package. The PR description flags this as intentional and distinct from Ariel's original proposal, and the reasoning holds up.
  • The deletions - install_path_for_sibling (dead now that #476 put everything on a real package path) and the do_handshake back-compat alias - are both called out explicitly in the PR description as answering prior review findings, and I confirmed there are no remaining callers of either (including in the test suite, which was updated to call ensure_session_handshake / the relocated _handshake_cache_path / _session_state_path directly).
  • core/_signing.py and core/_decision.py are a faithful, non-semantic-changing move - verify_with_key's malformed-base64 handling and modify_composition_violation's mutually-exclusive-shape checks read identically to before, just relocated.

One thing worth a second look by a maintainer rather than a blocker: the do_handshake alias was kept specifically "so out-of-tree adapter forks aren't broken by the rename" per its old docstring, and that guarantee is now gone. Given this is pre-1.0 reference-implementation code and the removal is an explicit, reviewed decision (not an oversight), I'm fine with it, but it's a real compatibility change worth a mention in the stack's final changelog when it lands.

Approving.

@rocklambros

Copy link
Copy Markdown
Collaborator

Closing this slice because PR #22 (the reference adapters for Claude Code, Cursor and NAT) merged into integration as 2630ec2, and that merge carries every slice in this stack. The top of the stack had the same files as PR #22's final commit, so nothing in this slice was left behind. Thanks, Bar, for cutting the adapters into pieces this size, because it made the review possible.

@rocklambros rocklambros closed this Nov 5, 2026
@github-project-automation github-project-automation Bot moved this from In progress to Done in ACS Project Tracker Nov 5, 2026
@bar-capsule
bar-capsule deleted the refimpl/adapters-02-core-client branch November 8, 2026 09:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants