Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# AGENTS.md

Codex entrypoint for the slack-chat-api repository.

## Start Here

Source of truth: https://github.com/open-cli-collective/slack-chat-api/blob/main/docs/development.md
Local convenience copy, if present: `docs/development.md`

## Shared Standards

Source of truth: https://github.com/open-cli-collective/cli-common/tree/main/docs
Local convenience copy, if present: `../cli-common/docs`

## Shared Automation

Source of truth: https://github.com/open-cli-collective/.github
Local convenience copy, if present: `../.github`

This file is an index. Keep Slack-specific guidance in `docs/development.md`
and shared conventions in the canonical repositories above.
203 changes: 12 additions & 191 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,200 +1,21 @@
# CLAUDE.md

This file provides context for AI assistants working with this codebase.
Claude entrypoint for the slack-chat-api repository.

## Project Overview
## Start Here

A command-line interface for Slack, supporting channel management, user lookup, messaging, and workspace info.
Source of truth: https://github.com/open-cli-collective/slack-chat-api/blob/main/docs/development.md
Local convenience copy, if present: `docs/development.md`

## Quick Commands
## Shared Standards

```bash
make build # Build binary to ./bin/slck
make test # Run tests with race detection and coverage
make lint # Run golangci-lint
make clean # Remove build artifacts
make install # Install to $GOPATH/bin
```
Source of truth: https://github.com/open-cli-collective/cli-common/tree/main/docs
Local convenience copy, if present: `../cli-common/docs`

## Project Structure
## Shared Automation

```
slack-chat-api/
├── main.go # Entry point
├── internal/
│ ├── cmd/ # Command implementations
│ │ ├── root/ # Root command and global flags
│ │ ├── channels/ # Channel commands (list, get, create, etc.)
│ │ ├── users/ # User commands (list, get)
│ │ ├── messages/ # Message commands (send, history, react, etc.)
│ │ ├── workspace/ # Workspace info command
│ │ └── config/ # Token management commands
│ ├── client/ # Slack API client wrapper
│ ├── keychain/ # Secure credential storage
│ ├── output/ # Output formatting (text/json/table)
│ └── version/ # Build-time version injection
├── .github/workflows/ci.yml # CI pipeline
├── .golangci.yml # Linter configuration (v2 format)
└── Makefile # Build targets
```
Source of truth: https://github.com/open-cli-collective/.github
Local convenience copy, if present: `../.github`

## Key Patterns

### Options Struct Pattern

All commands use an options struct with an injectable client for testability:

```go
type listOptions struct {
types string
excludeArchived bool
limit int
}

func runList(opts *listOptions, c *client.Client) error {
if c == nil {
var err error
c, err = client.New()
if err != nil {
return err
}
}
// Business logic...
}
```

### Output Formatting

Resource and mutation-success commands emit text or table only. Per cli-common `docs/output-and-rendering.md` §2 (enforced by `output.ParseFormat`'s closed-set `{text, table}`), JSON is reserved for local control-plane carve-outs — today only `slck config show --json`. Do NOT add per-command `--json` flags or `output.IsJSON()` branches to new resource commands.

The project-level JSON-vs-text contract lives in `ARCHITECTURE.md`:
JSON preserves upstream API semantics; text and table output may interpret
Slack data for terminal readability.

```go
// Default + table path:
output.Table(headers, rows) // For list commands
output.KeyValue("ID", item.ID) // For detail views

// Control-plane carve-out (config show pattern):
// local --json flag → call output.PrintJSON(envelope) directly.
```

### Global Flags

- `--output, -o` - Output format: text (default) or table
- `--no-color` - Disable colored output

## Testing

Tests use mock clients injected via the options struct:

```go
func TestRunList(t *testing.T) {
mockClient := &client.Client{...} // Mock setup
opts := &listOptions{limit: 10}
err := runList(opts, mockClient)
// Assertions...
}
```

Run tests: `make test`

Coverage report: `go tool cover -html=coverage.out`

## API Client

The `internal/client` package wraps the Slack API:

- `client.New()` - Creates client from token (env var or keychain)
- All API calls return typed responses
- Pagination handled internally with configurable limits

## Adding a New Command

1. Create file in appropriate `internal/cmd/<resource>/` directory
2. Define options struct with flags
3. Implement `newXxxCmd()` returning `*cobra.Command`
4. Implement `runXxx(opts, client)` with business logic
5. Register in the resource's root command
6. Add tests using mock client injection

## Common Issues

- **Token not found**: Run `slck init` or `slck set-credential --key bot_token --stdin`. Environment variables are NOT read at runtime (only as setup ingress, e.g. `init --bot-token-from-env`).
- **Permission denied**: Check bot token scopes in Slack app settings
- **Lint failures**: Run `make lint` locally before pushing
- **golangci-lint version**: CI uses v2.12.2 with v2 config format (Go 1.26)

## Credentials

slck stores credentials in the OS keyring via `cli-common/credstore` (Open
CLI Collective Secret-Handling Standard §2.4). The `internal/keychain`
package is a credstore adapter (no `security` shell-out, no plaintext file).
Non-secret config (`credential_ref`, `workspace`, `keyring.backend`) lives in
`~/.config/slack-chat-api/config.yml`. Ingress is only `slck init` /
`slck set-credential` (stdin or `--from-env`); never a flag/positional value.

**Backend selection** uses three user-configurable knobs that fall back to
auto-detect, in precedence order:

1. `--backend <name>` persistent flag (wired in `internal/cmd/root/root.go`
`WireBackendSelection`, parsed eagerly at `PersistentPreRunE` so an invalid
value fails before opening the keyring)
2. `SLACK_CHAT_API_KEYRING_BACKEND=<name>` env var (read by credstore directly)
3. `keyring.backend: <name>` in `config.yml` (validated at `openWith` time)
4. OS default

Supported names: `keychain`, `wincred`, `secret-service`, `file`, `memory`.
When the configured backend opens cleanly, `slck config show` surfaces the
resolved backend, its source (explicit / env / config / auto), and the
`keyring.backend` value from config.yml verbatim. An invalid
`keyring.backend` in config.yml errors at the first credential access
(including `slck config show`, which opens the store internally) rather
than at config load.

## Dependencies

- `github.com/open-cli-collective/cli-common` - shared credstore (OS keyring)
- `github.com/spf13/cobra` - CLI framework
- `golang.org/x/term` - no-echo passphrase prompt (file-backend opt-in)

(The HTTP Slack client is hand-rolled in `internal/client`; there is no
`slack-go`/`zalando` dependency.)

## Commit Conventions

Use conventional commits:

```
type(scope): description

feat(channels): add archive command
fix(messages): handle rate limiting
docs(readme): add configuration examples
```

| Prefix | Purpose | Triggers Release? |
|--------|---------|-------------------|
| `feat:` | New features | Yes |
| `fix:` | Bug fixes | Yes |
| `docs:` | Documentation only | No |
| `test:` | Adding/updating tests | No |
| `refactor:` | Code changes that don't fix bugs or add features | No |
| `chore:` | Maintenance tasks | No |
| `ci:` | CI/CD changes | No |

## CI & Release Workflow

Releases are automated with a dual-gate system to avoid unnecessary releases:

**Gate 1 - Path filter:** Only triggers when Go code changes (`**.go`, `go.mod`, `go.sum`)
**Gate 2 - Commit prefix:** Only `feat:` and `fix:` commits create releases

This means:
- `feat: add command` + Go files changed → release
- `fix: handle edge case` + Go files changed → release
- `docs:`, `ci:`, `test:`, `refactor:` → no release
- Changes only to docs, packaging, workflows → no release

**After merging a release-triggering PR:** The workflow creates a tag, which triggers GoReleaser to build binaries and publish to Homebrew. Chocolatey and Winget require manual workflow dispatch.
This file is an index. Keep Slack-specific guidance in `docs/development.md`
and shared conventions in the canonical repositories above.
118 changes: 118 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# slack-chat-api Development Guide

This is the repo-local guide for Slack-specific facts. Shared Open CLI
Collective standards and automation remain canonical in their own repositories.

## Project Overview

slack-chat-api builds the `slck` command-line interface for Slack. It supports
channel management, user lookup, messaging, reactions, message history, and
workspace information.

## Quick Commands

```bash
make build # build binary to ./bin/slck
make test # run tests with race detection
make test-cover # run tests with coverage output
make lint # run golangci-lint
make clean # remove build artifacts
make install # install to /usr/local/bin
```

## Repo Structure

```text
slack-chat-api/
├── cmd/slck/main.go
├── internal/
│ ├── cmd/ # Cobra command implementations
│ ├── client/ # Slack API client wrapper
│ ├── keychain/ # cli-common credstore adapter
│ ├── output/ # text/table rendering helpers
│ └── version/ # build-time version injection
├── ARCHITECTURE.md # project-level JSON-vs-text contract
├── .golangci.yml
└── Makefile
```

## Command Patterns

- Commands use small options structs with injectable clients for testability.
- New commands live under the appropriate `internal/cmd/<resource>/` package.
- Register new commands from the resource root command.
- Add tests around the command runner with a mock or injectable client.

## Output Contract

Resource and mutation-success commands emit text or table output. JSON is
reserved for local control-plane carve-outs, currently `slck config show --json`.
The project-level JSON-vs-text contract lives in `ARCHITECTURE.md`.

Source of truth: https://github.com/open-cli-collective/slack-chat-api/blob/main/ARCHITECTURE.md
Local convenience copy, if present: `ARCHITECTURE.md`

Shared output policy:

```md
Source of truth: https://github.com/open-cli-collective/cli-common/blob/main/docs/output-and-rendering.md
Local convenience copy, if present: `../cli-common/docs/output-and-rendering.md`
```

## Credentials And Config

`slck` stores credentials in the OS keyring through `cli-common/credstore`.
Non-secret config such as `credential_ref`, `workspace`, and `keyring.backend`
lives in `~/.config/slack-chat-api/config.yml`. Secret ingress is through
`slck init` or `slck set-credential`, using stdin or `--from-env` style inputs.

Shared credential and state policy:

```md
Source of truth: https://github.com/open-cli-collective/cli-common/blob/main/docs/working-with-secrets.md
Local convenience copy, if present: `../cli-common/docs/working-with-secrets.md`

Source of truth: https://github.com/open-cli-collective/cli-common/blob/main/docs/working-with-state.md
Local convenience copy, if present: `../cli-common/docs/working-with-state.md`
```

## Shared Repo Standards

Use these sources for shared repository policy. Do not copy their mechanics into
this guide.

```md
Source of truth: https://github.com/open-cli-collective/cli-common/blob/main/docs/command-surface.md
Local convenience copy, if present: `../cli-common/docs/command-surface.md`

Source of truth: https://github.com/open-cli-collective/cli-common/blob/main/docs/repo-layout.md
Local convenience copy, if present: `../cli-common/docs/repo-layout.md`

Source of truth: https://github.com/open-cli-collective/cli-common/blob/main/docs/ci.md
Local convenience copy, if present: `../cli-common/docs/ci.md`

Source of truth: https://github.com/open-cli-collective/cli-common/blob/main/docs/release.md
Local convenience copy, if present: `../cli-common/docs/release.md`

Source of truth: https://github.com/open-cli-collective/cli-common/blob/main/docs/distribution.md
Local convenience copy, if present: `../cli-common/docs/distribution.md`
```

## Shared Automation

Use `open-cli-collective/.github` for shared action and reusable workflow
implementations.

```md
Source of truth: https://github.com/open-cli-collective/.github
Local convenience copy, if present: `../.github`
```

## Dependencies

- `github.com/open-cli-collective/cli-common` - shared credential storage.
- `github.com/spf13/cobra` - command framework.
- `golang.org/x/term` - no-echo prompt support.

The Slack HTTP client is implemented in `internal/client`; this repo does not
use `slack-go` or `zalando`.
Loading