Skip to content

Commit 11088b1

Browse files
committed
Merge branch 'main' of github:BTreeMap/PromptPipe
2 parents 377d986 + ffcd336 commit 11088b1

63 files changed

Lines changed: 4346 additions & 561 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# AGENTS.md
2+
3+
Guide for autonomous coding agents working in the PromptPipe repository. Read this before touching the code.
4+
5+
## 1. Project Architecture
6+
7+
PromptPipe is a Go service that delivers personalized micro-habit prompts via WhatsApp, using an AI-driven conversation flow with tool calling.
8+
9+
### Component Map
10+
11+
```
12+
cmd/PromptPipe/main.go Entry point, flag/env parsing, wiring
13+
internal/api/ HTTP API endpoints (REST)
14+
internal/flow/ Conversation state machine, bot modules, tools
15+
internal/genai/ OpenAI client wrapper (tool calling, thinking)
16+
internal/messaging/ WhatsApp messaging service
17+
internal/models/ Data models, state types, flow types
18+
internal/store/ Storage backends (SQLite, Postgres, in-memory)
19+
internal/tone/ Tone adaptation (whitelist, EMA, validation)
20+
internal/util/ Env parsing, helpers
21+
internal/lockfile/ Single-instance lock
22+
internal/recovery/ Panic recovery
23+
internal/whatsapp/ WhatsApp client integration
24+
internal/testutil/ Shared test helpers
25+
prompts/ System prompt text files for each bot module
26+
docs/ Documentation
27+
```
28+
29+
### Conversation State Machine
30+
31+
The conversation flow dispatches between two primary modules:
32+
33+
- **IntakeModule** (`INTAKE` state): Collects user profile (habit domain, motivation, timing, anchor). Has access to save_user_profile, scheduler, generate_habit_prompt, and transition_state tools.
34+
- **FeedbackModule** (`FEEDBACK` state): Tracks habit completion, barriers, and tweaks. Has access to save_user_profile, scheduler, and transition_state tools.
35+
36+
Modules transition via `StateTransitionTool`. The `CoordinatorModule` exists as a legacy router but is not wired by default in production flow.
37+
38+
Profile data is stored as JSON blobs in the `flow_states` table via `StoreBasedStateManager`.
39+
40+
### Tool Calling Pattern
41+
42+
Each module builds system messages + chat history, then calls the LLM with tool definitions. When the LLM returns tool calls, the module executes them server-side in a loop (max 10 rounds) until a user-facing text response is produced.
43+
44+
## 2. Engineering Workflow
45+
46+
- **Read code first.** Code is the source of truth. Docs may lag behind.
47+
- **Small, reviewable commits** with clear messages (e.g., `feat(tone): ...`, `refactor: ...`, `test: ...`, `docs: ...`).
48+
- **Always run before finishing:**
49+
```sh
50+
go test ./...
51+
go vet ./...
52+
gofmt -w <modified files>
53+
```
54+
- **Update docs** when behavior or configuration changes.
55+
- **Prefer incremental refactors** with tests over big rewrites.
56+
57+
## 3. Tool and Schema Boundaries
58+
59+
### Profile Write Permissions
60+
61+
| Component | Can write profile? | Notes |
62+
|-----------|-------------------|-------|
63+
| IntakeModule | ✅ Yes | Primary profile builder |
64+
| FeedbackModule | ✅ Yes | Updates feedback fields and tone |
65+
| CoordinatorModule | ❌ No | Must not call save_user_profile |
66+
| PromptGeneratorTool | ❌ No | Read-only access to profile |
67+
68+
### Schema Evolution
69+
70+
- Tool schemas (OpenAI function definitions) should be evolved with backward-compatible, optional fields.
71+
- Validation happens at the Go server boundary, not in the LLM.
72+
- New tool parameters should default to safe values when absent.
73+
74+
### Security
75+
76+
- **No free-form user text** stored as instructions or tone data. Only whitelist tags.
77+
- **Whitelist enforcement** for all tone fields (see `internal/tone/tone.go`).
78+
- **Server-side gating**: LLM proposes, server decides. Even if the LLM sends invalid data, the server strips/rejects it.
79+
- Prompt injection mitigation: tone guide uses structured `<TONE POLICY>` tags, not user-controlled text.
80+
81+
## 4. Configuration
82+
83+
Environment variables and CLI flags are defined in `cmd/PromptPipe/main.go`. See [docs/configuration.md](docs/configuration.md) for the full reference.
84+
85+
**Precedence:** CLI flags > Environment variables > Defaults.
86+
87+
**Key vars:**
88+
- `DATABASE_DSN` / `DATABASE_URL`: SQLite or Postgres connection string.
89+
- `OPENAI_API_KEY`: Required for GenAI features.
90+
- `PROMPTPIPE_STATE_DIR`: Base directory for SQLite files and locks (default: `/var/lib/promptpipe`).
91+
- `API_ADDR`: HTTP listen address (default: `:8080`).
92+
93+
**Databases:** SQLite (default) or PostgreSQL. Migrations are `CREATE TABLE IF NOT EXISTS` in `internal/store/migrations_*.sql`. Profile data is stored as JSON in `flow_states.state_data`.
94+
95+
## 5. Testing Strategy
96+
97+
### Where Tests Live
98+
99+
- Unit tests: `*_test.go` files alongside source in each package.
100+
- Test helpers: `internal/testutil/testutil.go` (HTTP test server, assertions).
101+
- Flow test mocks: `internal/flow/test_helpers.go` (MockStateManager, MockGenAIClient, MockMessagingService).
102+
103+
### How to Run
104+
105+
```sh
106+
go test ./... # All tests
107+
go test ./internal/flow/ -v -run TestName # Specific test
108+
```
109+
110+
### What Requires New Tests
111+
112+
- Schema changes to tool definitions or profile structs.
113+
- New validation logic (e.g., tone whitelist, mutual exclusion).
114+
- Store round-trips for new data fields.
115+
- Prompt assembly logic changes.
116+
- State transition changes.
117+
118+
## 6. Code Style and Patterns
119+
120+
### Error Handling
121+
122+
- Return `error` from functions, wrap with `fmt.Errorf("context: %w", err)`.
123+
- Log errors at the call site with `slog.Error(...)`.
124+
- Use `slog.Debug(...)` for tracing, `slog.Info(...)` for significant events.
125+
126+
### Logging
127+
128+
- All logging uses `log/slog` with structured key-value pairs.
129+
- Log function name prefix: `"PackageName.FunctionName: message"`.
130+
- Include `participantID` in flow-related logs.
131+
132+
### Package Boundaries
133+
134+
- `internal/tone`: Self-contained module with no dependencies on `flow` or `store`. Keep it that way.
135+
- `internal/flow`: Contains all conversation logic. May import `tone`, `models`, `genai`, `store`.
136+
- `internal/models`: Shared type definitions. No business logic.
137+
- `internal/store`: Storage only. No flow logic.
138+
139+
### Adding New Features
140+
141+
Follow the `internal/tone` pattern:
142+
1. Create a focused package under `internal/`.
143+
2. Keep coupling minimal (import models, not flow).
144+
3. Add unit tests in the same package.
145+
4. Integration tests go in the consuming package (e.g., `internal/flow/`).
146+
5. Update docs and AGENTS.md if the feature affects architecture or boundaries.

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ build:
55
test:
66
go test ./...
77

8-
.PHONY: build test
8+
test-postgres:
9+
@echo "Run with: POSTGRES_DSN_TEST='postgres://user:pass@host:5432/dbname?sslmode=disable' make test-postgres"
10+
POSTGRES_DSN_TEST="$${POSTGRES_DSN_TEST}" go test ./internal/store/... -v -count=1
11+
12+
.PHONY: build test test-postgres

0 commit comments

Comments
 (0)