-
Notifications
You must be signed in to change notification settings - Fork 0
docs: restructure along Diátaxis — maturity tiers, non-goals, tutorial, how-tos #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
deffbbe
docs: restructure along Diátaxis — maturity tiers, non-goals, tutoria…
ThomasK33 1bb9b87
docs: address codex review findings — fix inaccurate claims in how-to…
ThomasK33 23ecad3
docs: address round-2 codex review findings
ThomasK33 4011fd5
docs: address round-3 codex review findings
ThomasK33 404ee57
docs: address round-4 codex review findings
ThomasK33 a3dd92c
docs: address round-5 codex review findings
ThomasK33 6a5407d
docs: address round-6 codex review finding
ThomasK33 4ecdab0
docs: address round-7 codex review findings
ThomasK33 4302a4d
docs: address round-8 codex review finding
ThomasK33 cea5b92
docs: address round-9 codex review findings
ThomasK33 266747e
docs: address round-10 codex review findings; reconcile with moved main
ThomasK33 aebddbb
docs: address round-11 codex review findings
ThomasK33 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
Large diffs are not rendered by default.
Oops, something went wrong.
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| # Chat SDK Go Documentation | ||
|
|
||
| User-facing documentation is organized along [Diátaxis](https://diataxis.fr/): | ||
| learning-oriented tutorials, task-oriented how-to guides, information-oriented | ||
| reference, and understanding-oriented explanation. | ||
|
|
||
| ## Tutorials | ||
|
|
||
| Start here if you are new to the SDK. | ||
|
|
||
| - [Your first Slack bot](tutorials/slack-bot.md) — zero to a running Slack bot | ||
| in under 30 minutes. | ||
|
|
||
| ## How-To Guides | ||
|
|
||
| Task-oriented guides for people already running a bot. | ||
|
|
||
| - [Choose a state backend](how-to/choose-a-state-backend.md) — memory, Redis, | ||
| Postgres, or NATS JetStream. | ||
| - [Defer long-running work (ack-then-work)](how-to/deferred-dispatch.md) — | ||
| acknowledge webhooks fast and run handlers on a detached context. | ||
| - [Handle slash commands](how-to/slash-commands.md) — route Slack slash | ||
| commands through `OnCommand`. | ||
| - [Handle interactive components](how-to/interactive-components.md) — buttons, | ||
| menus, Block Kit content, and modals. | ||
| - [Install into multiple workspaces (multi-tenant)](how-to/multi-tenant-install.md) — | ||
| resolve per-tenant credentials with an `InstallStore`. | ||
| - [Run Linear agent sessions](how-to/linear-agent-sessions.md) — build a Linear | ||
| agent with thoughts, responses, actions, elicitations, and plans. | ||
|
|
||
| ## Reference | ||
|
|
||
| - [API and package reference](reference.md) — pkg.go.dev pointers, module | ||
| layout, and per-adapter capability status. | ||
| - [Linear agent capability gaps](linear-agent-capabilities.md) — tracked list | ||
| of Linear agent APIs the adapter does not yet wrap. | ||
|
|
||
| ## Explanation | ||
|
|
||
| - [Architecture and design decisions](explanation.md) — an index over | ||
| [`CONTEXT.md`](../CONTEXT.md) (the ubiquitous language and architecture | ||
| document) and the [ADRs](adr/) that record every significant decision. | ||
|
|
||
| ## Non-User Documentation | ||
|
|
||
| - [`docs/agents/`](agents/) — instructions for coding agents working on this | ||
| repository, not for SDK users. |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,35 @@ | ||
| # Issue tracker: Local Markdown | ||
| # Issue tracker: GitHub Issues | ||
|
|
||
| Issues and PRDs for this repo live as markdown files in `.scratch/`. | ||
| The public source of truth for this repo's roadmap, feature requests, and bug | ||
| reports is GitHub issues: | ||
|
|
||
| ## Conventions | ||
| https://github.com/coder/chat/issues | ||
|
|
||
| Anything user-facing — planned work, accepted/rejected proposals, bug state — | ||
| belongs there. Use `gh issue` to read and update it. | ||
|
|
||
| ## `.scratch/` is internal working notes only | ||
|
|
||
| The `.scratch/` directory holds internal working notes: PRDs, implementation | ||
| breakdowns, and drafts that agents produce while working. It is not a public | ||
| roadmap, it makes no promises, and nothing in it should be treated as | ||
| authoritative over GitHub issues. When a scratch note graduates into real | ||
| planned work, file a GitHub issue for it. | ||
|
|
||
| ### Conventions for `.scratch/` | ||
|
|
||
| - One feature per directory: `.scratch/<feature-slug>/` | ||
| - The PRD is `.scratch/<feature-slug>/PRD.md` | ||
| - Implementation issues are `.scratch/<feature-slug>/issues/<NN>-<slug>.md`, numbered from `01` | ||
| - Triage state is recorded as a `Status:` line near the top of each issue file (see `triage-labels.md` for the role strings) | ||
| - Implementation notes are `.scratch/<feature-slug>/issues/<NN>-<slug>.md`, numbered from `01` | ||
| - Triage state is recorded as a `Status:` line near the top of each file (see `triage-labels.md` for the role strings) | ||
| - Comments and conversation history append to the bottom of the file under a `## Comments` heading | ||
|
|
||
| ## When a skill says "publish to the issue tracker" | ||
|
|
||
| Create a new file under `.scratch/<feature-slug>/` (creating the directory if needed). | ||
| Create a GitHub issue with `gh issue create`. Use `.scratch/<feature-slug>/` | ||
| only for supporting working notes that are not ready to be public. | ||
|
|
||
| ## When a skill says "fetch the relevant ticket" | ||
|
|
||
| Read the file at the referenced path. The user will normally pass the path or the issue number directly. | ||
| If the reference is a number or URL, read the GitHub issue with | ||
| `gh issue view`. If the reference is a path, read the file at that path. | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| # Architecture And Design Decisions | ||
|
|
||
| Chat SDK Go's design is documented in two places, and this page is the index | ||
| over both: | ||
|
|
||
| - [`CONTEXT.md`](../CONTEXT.md) — the ubiquitous language and architecture | ||
| document. It defines every domain term precisely (with the synonyms to | ||
| avoid), states the architectural invariants as explicit relationships, and | ||
| records resolved ambiguities against upstream Vercel Chat SDK behavior. | ||
| - [`docs/adr/`](adr/) — Architecture Decision Records. Every significant | ||
| decision has one, including the decisions *not* to build something. | ||
|
|
||
| ## Reading CONTEXT.md | ||
|
|
||
| If you want to understand the system, read `CONTEXT.md` top to bottom; it is | ||
| the single most information-dense document in the repository. Its `Language` | ||
| section groups the vocabulary by area — runtime lifecycle, the platform | ||
| adapter boundary, Linear session lifecycle, threads and routing, the | ||
| event/message model, dispatch and concurrency, observability, state and | ||
| history, content and formatting, and tenancy and identity. The | ||
| `Relationships` section is the closest thing to a formal specification of the | ||
| runtime's invariants, and `Flagged ambiguities` explains where and why the | ||
|
ThomasK33 marked this conversation as resolved.
|
||
| design deliberately diverges from Vercel Chat SDK. | ||
|
|
||
| ## Decision Records | ||
|
|
||
| | ADR | Decision | Status | | ||
| | --- | --- | --- | | ||
| | [0001](adr/0001-linear-app-actor-slice.md) | Linear app-actor slice before a full Linear adapter | Accepted | | ||
| | [0002](adr/0002-async-dispatch.md) | Deferred runtime dispatch (ack-then-work) | Accepted | | ||
| | [0003](adr/0003-slash-commands.md) | Command Events and slash command routing | Accepted | | ||
| | [0004](adr/0004-interactive-components.md) | Interaction Events and native content instead of a card DSL | Accepted | | ||
| | [0005](adr/0005-rate-limit-handling.md) | Rate-limit retry lives in adapters, with typed `RateLimited` errors | Accepted | | ||
| | [0006](adr/0006-multi-tenant-install.md) | Multi-tenant installs via app-implemented `InstallStore`; OAuth flows stay app-owned | Accepted | | ||
| | [0007](adr/0007-teams-adapter.md) | Microsoft Teams adapter approach (Bot Framework, direct HTTP) | Proposed — gated on a spike | | ||
| | [0008](adr/0008-linear-full-adapter.md) | Full Linear agent activity surface (thought/response/action/elicitation/error) plus session updates (plans, external URLs) | Accepted | | ||
| | [0009](adr/0009-message-history.md) | Message history stays application-owned; optional storage-free `HistoryReader` | Accepted | | ||
| | [0010](adr/0010-observability.md) | Optional `Observer` seam; no OpenTelemetry in core | Accepted | | ||
| | [0011](adr/0011-resumable-streaming.md) | Resumable streaming deferred from core, not foreclosed | Proposed | | ||
| | [0012](adr/0012-concurrency-strategy.md) | Concurrency strategy expansion (`queue` implemented; `burst`/`debounce`/`concurrent` staged) | Accepted (staged) | | ||
| | [0013](adr/0013-linear-generic-comments.md) | Linear generic issue/comment participation | Accepted | | ||
| | [0014](adr/0014-nats-state-adapter.md) | NATS JetStream state adapter | Accepted | | ||
|
|
||
| ## The Short Version | ||
|
|
||
| For readers who want the model in five paragraphs: | ||
|
|
||
| **The runtime coordinates conversations; it does not own your product.** | ||
| `chat.Chat` verifies webhooks through adapters, normalizes platform payloads | ||
| into events, dedupes them, serializes work per thread with token-owned lock | ||
| leases, and routes to your single-slot handlers. Everything your product | ||
| stores — transcripts, user records, workflow state — lives in your database, | ||
| keyed by the opaque `ThreadID`. | ||
|
|
||
| **Adapters own the platform boundary.** Signature verification, payload | ||
| normalization, outbound rendering, rate-limit retries, and platform quirks | ||
| live inside the adapter. Platform-specific power is reached deliberately via | ||
| typed adapter access (`chat.AdapterAs`), never by making raw platform structs | ||
| the normal API. | ||
|
|
||
| **State is required and small.** Subscriptions, dedupe marks, and locks — | ||
| that is all. Memory for development; Redis, Postgres, or NATS for production. | ||
|
|
||
| **Events are broader than messages.** A slash command and a button click are | ||
| normalized events with their own hooks, not messages. All events ride the | ||
| same dispatch spine. | ||
|
|
||
| **Semantic compatibility, not feature parity.** Vercel Chat SDK's | ||
| conversation model is the precedent; its TypeScript API shapes are not. Where | ||
| Go idioms or operational safety argue otherwise, this SDK deliberately | ||
| diverges and documents the divergence. | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| # How To Choose A State Backend | ||
|
|
||
| Runtime state is required: the runtime stores subscribed-thread membership, | ||
| event dedupe marks, and thread lock leases in a `chat.State`. It is | ||
| coordination state, not product state — keep your application's own data in | ||
| your own database keyed by `ThreadID`. | ||
|
|
||
| Four implementations ship today: | ||
|
|
||
| | Backend | Module | Use for | | ||
| | --- | --- | --- | | ||
| | Memory | `github.com/coder/chat/state/memory` (in the core module) | Tests and local demos. Lost on restart. | | ||
| | Redis | `github.com/coder/chat/state/redis` | Production, horizontally scaled deployments. | | ||
| | Postgres | `github.com/coder/chat/state/postgres` | Production, when Postgres is already your coordination store. | | ||
| | NATS JetStream | `github.com/coder/chat/state/nats` | Production, when you already run NATS with JetStream. | | ||
|
|
||
| Redis, Postgres, and NATS live in separate Go modules so applications that only | ||
| need core, Slack, or memory state do not pull their dependencies. | ||
|
|
||
| ## Memory | ||
|
|
||
| ```go | ||
| import "github.com/coder/chat/state/memory" | ||
|
|
||
| bot, err := chat.New(ctx, | ||
| chat.WithState(memory.New()), | ||
| chat.WithAdapter(adapter), | ||
| ) | ||
| ``` | ||
|
|
||
| Memory state is for tests and local development only. Subscriptions and dedupe | ||
| data vanish when the process exits, so a restarted bot forgets which threads it | ||
| was in and may re-handle redelivered events. | ||
|
|
||
| ## Redis | ||
|
|
||
| ```sh | ||
| go get github.com/coder/chat/state/redis | ||
| ``` | ||
|
ThomasK33 marked this conversation as resolved.
|
||
|
|
||
| ```go | ||
| import ( | ||
| "github.com/redis/go-redis/v9" | ||
|
|
||
| chatredis "github.com/coder/chat/state/redis" | ||
| ) | ||
|
|
||
| redisState, err := chatredis.New(ctx, chatredis.Options{ | ||
| Client: redis.NewClient(&redis.Options{Addr: os.Getenv("REDIS_ADDR")}), | ||
| Prefix: "mybot", // see "One namespace per bot application" below | ||
| }) | ||
| ``` | ||
|
|
||
| The runnable example, including a `compose.yaml` for a local Redis, is | ||
| [`examples/slack-redis-state`](../../examples/slack-redis-state/README.md). | ||
|
|
||
| ## Postgres | ||
|
|
||
| ```sh | ||
| go get github.com/coder/chat/state/postgres | ||
| ``` | ||
|
|
||
| ```go | ||
| import ( | ||
| "github.com/jackc/pgx/v5/pgxpool" | ||
|
|
||
| chatpostgres "github.com/coder/chat/state/postgres" | ||
| ) | ||
|
|
||
| pool, err := pgxpool.New(ctx, os.Getenv("DATABASE_URL")) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| pgState, err := chatpostgres.New(ctx, chatpostgres.Options{ | ||
| Pool: pool, | ||
| Namespace: "mybot", // see "One namespace per bot application" below | ||
| }) | ||
| ``` | ||
|
|
||
| The Postgres state initializes its own schema (subscription, event, and lock | ||
| tables) on startup. The runnable example is | ||
| [`examples/slack-postgres-state`](../../examples/slack-postgres-state/README.md). | ||
|
|
||
| ## NATS JetStream | ||
|
|
||
| ```sh | ||
| go get github.com/coder/chat/state/nats | ||
| ``` | ||
|
|
||
| ```go | ||
| import ( | ||
| natsgo "github.com/nats-io/nats.go" | ||
|
|
||
| chatnats "github.com/coder/chat/state/nats" | ||
| ) | ||
|
|
||
| conn, err := natsgo.Connect(os.Getenv("NATS_URL")) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| natsState, err := chatnats.New(ctx, chatnats.Options{ | ||
| Conn: conn, | ||
| Prefix: "mybot", // see "One namespace per bot application" below | ||
| // DedupeTTL and ThreadLockTTL default to the runtime defaults (24h and | ||
| // 2m) and must match your RuntimeOptions. | ||
| }) | ||
| ``` | ||
|
|
||
| NATS state stores subscriptions, dedupe marks, and locks in three JetStream | ||
| Key-Value buckets with bucket-level TTLs (see | ||
| [ADR 0014](../adr/0014-nats-state-adapter.md)). Because JetStream TTLs are | ||
| per-bucket, the dedupe and lock TTLs are fixed at construction time. The | ||
| runnable example is | ||
| [`examples/slack-nats-state`](../../examples/slack-nats-state/README.md). | ||
|
|
||
| ## One Namespace Per Bot Application | ||
|
|
||
| The `Prefix`/`Namespace` options default to `chat`. If two *independent* bot | ||
| applications share one Redis, Postgres, or NATS service with the default, | ||
| their subscription, dedupe, and lock records collide — thread IDs carry | ||
| platform tenant/channel identity but no application identity, so app A | ||
| subscribing a thread can route that thread's follow-ups into app B's | ||
| `OnSubscribedMessage`, and one app's locks can suppress the other's events. | ||
| Give every bot application its own stable namespace, shared only by that | ||
| app's replicas (replicas must share the namespace — that is what makes | ||
| dedupe and locking work across them). | ||
|
|
||
| ## How To Decide | ||
|
|
||
| - Writing tests or following the tutorial: use memory. | ||
| - Already running Redis: use Redis. Same for Postgres and NATS — the backends | ||
| are contract-equivalent, so pick the one you already operate. | ||
| - Running more than one bot replica: any of the durable backends works; all | ||
| three implement the same token-owned lock lease and dedupe contract, which is | ||
| what makes horizontal scaling safe. | ||
|
|
||
| All backends are exercised by the same conformance suite; Redis and Postgres | ||
| integration tests run against real backends via Testcontainers, and NATS tests | ||
| run against an embedded JetStream server. | ||
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.