Skip to content

Architectural drift: business logic in the CLI/agent front door instead of shared SDK services #350

Description

@bordumb

Summary

Business rules live in the CLI presentation layer (and the agent front door) instead of shared SDK
services, violating the project's own architecture rule:

CLAUDE.md: "Business logic must live in SDK/Core, never in the CLI presentation layer."

Because the logic isn't shared, copies drift — and that drift has already produced shipped bugs.

Why this matters now

The --repo confused-deputy class (multiple commands silently ignoring the global --repo flag and
acting on the default ~/.auths store — including a destructive reset --repo that wiped the wrong
store) was a direct symptom of this drift: storage-path resolution was duplicated across ~6 commands
instead of one shared helper, and the copies diverged so several forgot the flag. "Logic in the front door
drifts" is not hypothetical here — it was the root cause of a whole class of bugs.

Evidence

  • configcrates/auths-cli/src/commands/config.rs matches config keys, parses/validates values
    (parse_cache_policy, parse_bool, duration parsing), and loads/saves config directly — all inline in
    the command. CLAUDE.md explicitly names this leak: "Config management → should be in SDK as
    ConfigService."
    Still present.
  • agentagent env/lock/unlock/start/stop implement agent lifecycle in the command layer rather
    than a shared service, so the agent front door carries the same problem.
  • ~35 domain commands call no SDK capability at all (per a capability-mapping audit of
    auths-cli/src/commands against the auths-sdk public surface), e.g. multi-sig begin/combine/sign,
    approval grant/list, id bind-idp/migrate. This is a heuristic signal; config + agent are
    confirmed by reading the source.
  • The existing guard is only half the rule. scripts/check_sdk_boundary.sh catches the CLI
    importing auths_core/auths_id/auths_storage directly — but it does not catch domain logic
    written inline in the CLI. So a command can branch on domain rules / parse / validate without importing a
    lower crate and the guard passes clean (exactly how config.rs slips through).

Scope

  • Affected: the CLI and the agent front doors.
  • Not affected: the HTTP API (auths-api, ~1.2k lines, no domain-logic patterns) is genuinely thin —
    good, and the model to follow.

Proposed work

  1. Extract config logic into an SDK ConfigService; the CLI config command becomes a thin translator.
  2. Move agent lifecycle (env/lock/unlock, daemon management) into a shared SDK service.
  3. Consolidate storage-path resolution behind one helper used everywhere. (Partly done: --repo is now
    threaded through resolve_repo_path for several commands on the security-fix branch; finish the
    remaining holdouts.)
  4. Add a logic-leak guard to CI — fail when a CLI command performs domain logic without delegating to
    an SDK service. Extend check_sdk_boundary.sh beyond imports, or wire in a capability-coverage check
    (a command that maps to zero SDK capabilities is a candidate leak).
  5. Triage the remaining ~35 no-SDK-capability commands: delegate to SDK, or document why each is
    legitimately presentation-only.

Acceptance

  • config and agent business logic lives in SDK services; the CLI calls them.
  • A CI check fails when a new CLI command embeds domain logic without an SDK call.
  • The ~35-command list is triaged (delegated or justified with a reason).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions