Skip to content

feat(amico-run): ship amico-slack as the package's Slack client bin (unified-fleet slice 2) #429

Description

@aarontrowbridge

Important

Problem

The only usable Slack poster (~/.local/bin/amico-slack, Python) is hand-planted on one machine with no versioned source — the product has no Slack client, and the unified-fleet spec's slice 2 ships one.

Approach

Port the CLI into @amicode/amico-run as a zero-dep Node bin (node:https, the existing launcher/bin pattern), absorbing the DM path as a dm command so the internal httpx client can retire. One client — the Python script becomes the executable reference, then yields authority the moment the bin lands.

Approaches Considered

  • Ship the Python script inside the extension — rejected: Python runtime friction on user machines; the Node bin matches amico-run's launcher pattern.
  • Keep both clients indefinitely — rejected: two clients is the disease being cured.
  • (chosen) Node bin port with ported tests.

Acceptance Criteria

  1. The bin supports send (incl. --file, --thread, --as-user), read, whois, delete, status, and new dm <email|@handle>.
  2. Voice contract intact: default posts as the app with no footer; --as-user appends _de Amico_; legacy Authored by Amico stripped idempotently (ported tests prove it).
  3. Token layering: credential store → ~/.amico/slack/token (0600) → SLACK_BOT_TOKEN env; absent all → clean "no Slack configured" exit, never a crash.
  4. ~/.local/bin/amico-slack becomes a symlink to the shipped bin; the SKILL.md cli_tool resolves from PATH.
  5. The papers-digest verb and morning-brief workflow post through the bin; the internal httpx SlackClient retires to the email-lookup only, or fully if dm covers it.
  6. With no Slack configured anywhere, the extension and verbs are inert and silent (product guarantee).

Key Decisions

  • Port, not rewrite: the Python script is the executable reference; port its test cases (footer idempotence, mrkdwn flattening, mention resolution) alongside.
  • dm absorbs users.lookupByEmailconversations.openchat.postMessage (needs users:read.email — added in slice 0).

Source

  • Durable record: specs/spec-20260818-150711-unified-amico-fleet-slack.md (personal vault, rev 2) — slice 2.

Metadata

Metadata

Labels

hitlHuman-in-the-loop — needs human review/decision

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions