Skip to content

Commit 13af65d

Browse files
committed
Add add-inbox-triage change proposal
1 parent 6ac1d32 commit 13af65d

File tree

7 files changed

+532
-0
lines changed

7 files changed

+532
-0
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Design: Inbox Capture and Triage System
2+
3+
## Context
4+
5+
JDO users need to capture thoughts quickly from various contexts without interactive TUI sessions. The system should gracefully handle ambiguous input by queuing it for later AI-assisted classification rather than forcing immediate type decisions.
6+
7+
Key stakeholders:
8+
- End users capturing ideas on-the-go
9+
- External automation scripts (shell aliases, iOS Shortcuts, webhooks)
10+
- The AI agent that assists with classification
11+
12+
## Goals / Non-Goals
13+
14+
### Goals
15+
- Enable fire-and-forget capture from CLI without TUI
16+
- Provide AI-assisted triage workflow for classifying captured items
17+
- Handle vague chat input gracefully by creating triage items
18+
- Show users when items need attention via home screen indicator
19+
20+
### Non-Goals
21+
- Real-time push notifications to running TUI (deferred to future)
22+
- Complex inbox management (folders, tags, priorities)
23+
- External API/webhook server (CLI-only for v1)
24+
- Automatic classification without user confirmation
25+
26+
## Decisions
27+
28+
### Decision 1: Reuse Draft model with UNKNOWN type
29+
30+
**Choice**: Add `UNKNOWN = "unknown"` to existing `EntityType` enum rather than creating a new `InboxItem` model.
31+
32+
**Rationale**:
33+
- Draft already handles partial objects with `partial_data` JSON field
34+
- Consistent pattern: triage items are just drafts without a known type
35+
- When classified, simply update `entity_type` and continue normal creation flow
36+
- Reduces schema complexity and migration needs
37+
38+
**Alternatives considered**:
39+
- New `InboxItem` table: More explicit but duplicates Draft functionality
40+
- Separate inbox file (JSON/SQLite): Adds sync complexity between inbox and main DB
41+
42+
### Decision 2: CLI subcommand vs separate entry point
43+
44+
**Choice**: Add `jdo capture "text"` as a subcommand using Click/Typer.
45+
46+
**Rationale**:
47+
- Single `jdo` command with subcommands is more discoverable
48+
- Consistent with common CLI patterns (git, docker, etc.)
49+
- Future subcommands (e.g., `jdo status`) share same entry point
50+
51+
**Alternatives considered**:
52+
- Separate `jdo-capture` binary: Simpler initially but fragments UX
53+
- Stdin mode (`echo "text" | jdo capture`): Added complexity for marginal benefit
54+
55+
### Decision 3: DB-only notification (no file watcher)
56+
57+
**Choice**: Check for triage items on home screen mount and `/triage` command only.
58+
59+
**Rationale**:
60+
- File watching adds complexity (platform-specific, dependencies, race conditions)
61+
- SQLite with WAL mode handles concurrent CLI/TUI access well
62+
- Acceptable UX: users see count when they launch or navigate home
63+
- Can add simple polling timer later if real-time becomes important
64+
65+
**Alternatives considered**:
66+
- inotify/watchdog file watcher: Platform-specific, adds dependencies
67+
- Unix socket IPC: Complex, overkill for this use case
68+
- Polling timer: Could add as enhancement (check every 30s)
69+
70+
### Decision 4: Triage workflow in chat (not dedicated screen)
71+
72+
**Choice**: Implement triage as a chat-based conversation flow.
73+
74+
**Rationale**:
75+
- Natural conversational UX consistent with existing creation flows
76+
- Reuses existing chat infrastructure (messages, data panel)
77+
- Users familiar with chat patterns for object creation
78+
- AI responses feel natural in chat context
79+
80+
**Alternatives considered**:
81+
- Dedicated TriageScreen: Cleaner separation but duplicates UI patterns
82+
- Modal overlay: Too restrictive for multi-item workflow
83+
84+
### Decision 5: FIFO queue with skip-to-back behavior
85+
86+
**Choice**: Skipped items stay at front of queue (true FIFO).
87+
88+
**Rationale**:
89+
- Prevents items getting "lost" at back of growing queue
90+
- User explicitly chose to skip; they'll see it again next triage session
91+
- Simple mental model: items processed in capture order
92+
93+
**Alternatives considered**:
94+
- Skip moves to back: Item could get buried
95+
- Priority system: Over-engineering for v1
96+
97+
### Decision 6: AI confidence threshold hardcoded
98+
99+
**Choice**: Use hardcoded reasonable defaults for classification confidence.
100+
101+
**Rationale**:
102+
- Avoid premature optimization
103+
- Can tune based on real user feedback
104+
- Expose as setting later if needed
105+
106+
**Implementation**: If AI confidence < 0.7, ask clarifying question rather than suggesting type.
107+
108+
## Risks / Trade-offs
109+
110+
| Risk | Mitigation |
111+
|------|------------|
112+
| AI misclassifies items | User always confirms; easy to change type |
113+
| Queue grows unbounded | Home screen count creates visibility/incentive |
114+
| CLI/TUI DB contention | SQLite WAL mode; tested concurrent access |
115+
| Scope creep (inbox features) | Explicit non-goals; defer enhancements |
116+
117+
## Migration Plan
118+
119+
No migration needed - all changes are additive:
120+
1. `UNKNOWN` enum value is new, existing drafts unaffected
121+
2. New CLI command doesn't affect existing `jdo` TUI entry point
122+
3. Home screen indicator only shows when count > 0
123+
124+
## Open Questions
125+
126+
None - all questions resolved during design discussion:
127+
- Real-time vs on-demand: On-demand (check on mount/command)
128+
- Triage UI: Chat-based
129+
- AI confidence: Ask simple clarifying questions when low
130+
- `/triage` scope: Available from anywhere
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Change: Add Inbox Capture and Triage System
2+
3+
## Why
4+
5+
Users need a way to quickly capture ideas, tasks, and commitments from external contexts (scripts, shell aliases, iOS Shortcuts, webhooks) without launching the full TUI. Currently, creating any object requires interactive TUI use with explicit type selection. This friction causes users to lose ideas or defer capture until they forget.
6+
7+
Additionally, when users enter vague descriptions in chat without specifying object type, the system has no graceful fallback - it either guesses wrong or fails to act.
8+
9+
## What Changes
10+
11+
### New Capability: `inbox`
12+
13+
- **CLI capture command**: `jdo capture "text"` stores raw text for later triage
14+
- **Triage workflow**: AI-assisted classification of captured items into proper object types
15+
- **Triage command**: `/triage` starts guided processing of inbox items
16+
17+
### Modified Capabilities
18+
19+
- **data-persistence**: Add `UNKNOWN` to `EntityType` enum for unclassified items
20+
- **tui-chat**: Add `/triage` command, handle vague chat input by creating triage items
21+
- **jdo-app**: Add home screen triage indicator with count and `t` key binding
22+
23+
## Impact
24+
25+
- Affected specs: `data-persistence` (modified), `tui-chat` (modified), `jdo-app` (modified), `inbox` (new)
26+
- Affected code:
27+
- `src/jdo/models/draft.py` - EntityType enum
28+
- `src/jdo/db/session.py` - triage query helper
29+
- `src/jdo/cli.py` - new capture CLI
30+
- `src/jdo/commands/triage.py` - triage handler
31+
- `src/jdo/ai/triage.py` - AI classification
32+
- `src/jdo/screens/home.py` - triage indicator
33+
- `src/jdo/screens/chat.py` - message handling
34+
- `pyproject.toml` - CLI entry point
35+
- Breaking changes: None - all additions are backwards compatible
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
## MODIFIED Requirements
2+
3+
### Requirement: Query Support
4+
5+
The system SHALL support SQLModel query patterns for filtering and ordering.
6+
7+
#### Scenario: Filter by field value
8+
- **WHEN** `session.exec(select(Model).where(Model.field == value))`
9+
- **THEN** only matching entities are returned
10+
11+
#### Scenario: Filter by multiple conditions
12+
- **WHEN** `session.exec(select(Model).where(Model.a == x, Model.b == y))`
13+
- **THEN** entities matching all conditions are returned
14+
15+
#### Scenario: Order results
16+
- **WHEN** `session.exec(select(Model).order_by(Model.field))`
17+
- **THEN** results are returned in ascending order by field
18+
19+
#### Scenario: Limit results
20+
- **WHEN** `session.exec(select(Model).limit(n))`
21+
- **THEN** at most n entities are returned
22+
23+
#### Scenario: Query triage items
24+
- **WHEN** `get_triage_items(session)` is called
25+
- **THEN** Draft records with `entity_type=UNKNOWN` are returned ordered by `created_at` ascending (FIFO)
26+
27+
#### Scenario: Count triage items
28+
- **WHEN** `get_triage_count(session)` is called
29+
- **THEN** the count of Draft records with `entity_type=UNKNOWN` is returned
30+
31+
## ADDED Requirements
32+
33+
### Requirement: EntityType UNKNOWN Value
34+
35+
The system SHALL support an UNKNOWN entity type for items needing triage.
36+
37+
#### Scenario: UNKNOWN in EntityType enum
38+
- **WHEN** a Draft is created for triage
39+
- **THEN** `entity_type` can be set to `EntityType.UNKNOWN`
40+
41+
#### Scenario: UNKNOWN drafts excluded from normal draft restore
42+
- **WHEN** the app checks for pending drafts on startup
43+
- **THEN** drafts with `entity_type=UNKNOWN` are not included in the restore prompt
44+
- **AND** they are handled separately via the triage system
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# inbox Specification
2+
3+
## Purpose
4+
5+
Define the inbox capture and triage system for JDO, enabling quick capture of raw text from external sources and AI-assisted classification into proper domain objects.
6+
7+
## ADDED Requirements
8+
9+
### Requirement: CLI Capture Command
10+
11+
The system SHALL provide a CLI command to capture raw text for later triage.
12+
13+
#### Scenario: Capture text from command line
14+
- **WHEN** user runs `jdo capture "finish the quarterly report"`
15+
- **THEN** a Draft is created with `entity_type=UNKNOWN` and `partial_data={"raw_text": "finish the quarterly report"}`
16+
- **AND** the command prints "Captured for triage" and exits with code 0
17+
18+
#### Scenario: Capture empty text rejected
19+
- **WHEN** user runs `jdo capture ""`
20+
- **THEN** the command prints an error message and exits with code 1
21+
- **AND** no Draft is created
22+
23+
#### Scenario: Capture with special characters
24+
- **WHEN** user runs `jdo capture "meeting with Sarah @ 3pm re: budget"`
25+
- **THEN** the text is stored exactly as provided, preserving special characters
26+
27+
#### Scenario: Multiple captures create separate items
28+
- **WHEN** user runs `jdo capture "item 1"` then `jdo capture "item 2"`
29+
- **THEN** two separate Draft records are created with sequential timestamps
30+
31+
### Requirement: Triage Command
32+
33+
The system SHALL provide a `/triage` command to process inbox items.
34+
35+
#### Scenario: Start triage with items
36+
- **WHEN** user types `/triage` and there are items needing triage
37+
- **THEN** the system displays the first item with AI analysis and action options
38+
39+
#### Scenario: Start triage with no items
40+
- **WHEN** user types `/triage` and there are no items needing triage
41+
- **THEN** the system responds "No items to triage. Your inbox is empty."
42+
43+
#### Scenario: Triage available from chat
44+
- **WHEN** user is on the chat screen and types `/triage`
45+
- **THEN** triage mode starts in the current chat session
46+
47+
#### Scenario: Triage available from home
48+
- **WHEN** user presses `t` on the home screen with items needing triage
49+
- **THEN** the system navigates to chat and starts triage mode
50+
51+
### Requirement: AI Classification
52+
53+
The system SHALL use AI to analyze and classify triage items.
54+
55+
#### Scenario: AI suggests object type
56+
- **WHEN** a triage item is displayed
57+
- **THEN** the AI analyzes the text and suggests: object type, confidence level, and detected entities (stakeholders, dates, potential links)
58+
59+
#### Scenario: High confidence suggestion
60+
- **WHEN** AI confidence is high (>= 0.7)
61+
- **THEN** the AI presents its suggestion directly: "This looks like a Commitment to Sarah, due Friday."
62+
63+
#### Scenario: Low confidence clarification
64+
- **WHEN** AI confidence is low (< 0.7)
65+
- **THEN** the AI asks a simple clarifying question: "Is this something you need to do, or a goal you want to achieve?"
66+
67+
#### Scenario: Entity detection
68+
- **WHEN** AI analyzes "finish report for Sarah by Friday"
69+
- **THEN** it detects: stakeholder "Sarah" (matches existing if present), due date "Friday", and suggests linking opportunities
70+
71+
### Requirement: Triage Actions
72+
73+
The system SHALL support user actions during triage.
74+
75+
#### Scenario: Accept suggestion
76+
- **WHEN** user selects "Accept" (or presses 1)
77+
- **THEN** the Draft's `entity_type` is updated to the suggested type
78+
- **AND** the normal creation flow begins with pre-filled fields from AI extraction
79+
80+
#### Scenario: Change type
81+
- **WHEN** user selects "Change type" (or presses 2)
82+
- **THEN** the system prompts: "What type? [c]ommitment, [g]oal, [t]ask, [v]ision, [m]ilestone"
83+
- **AND** user selection updates the Draft and proceeds to creation flow
84+
85+
#### Scenario: Delete item
86+
- **WHEN** user selects "Delete" (or presses 3)
87+
- **THEN** the Draft is permanently deleted
88+
- **AND** the system proceeds to the next triage item
89+
90+
#### Scenario: Skip item
91+
- **WHEN** user selects "Skip" (or presses 4)
92+
- **THEN** the system proceeds to the next item
93+
- **AND** the skipped item remains at the front of the queue for next triage session
94+
95+
### Requirement: Triage Queue Management
96+
97+
The system SHALL manage the triage queue with FIFO ordering.
98+
99+
#### Scenario: FIFO ordering
100+
- **WHEN** multiple items need triage
101+
- **THEN** they are presented in order of capture (oldest first)
102+
103+
#### Scenario: Queue persists across sessions
104+
- **WHEN** user exits triage before completing all items
105+
- **THEN** remaining items stay in the queue for the next session
106+
107+
#### Scenario: Partial progress saved
108+
- **WHEN** user accepts a type but exits before completing creation
109+
- **THEN** the item becomes a normal Draft with the confirmed `entity_type`
110+
- **AND** it is removed from the triage queue (no longer UNKNOWN)
111+
112+
#### Scenario: Triage completion
113+
- **WHEN** user processes the last item in the queue
114+
- **THEN** the system displays "Triage complete! All items processed."
115+
116+
### Requirement: Vague Chat Input Detection
117+
118+
The system SHALL detect vague input in chat and offer triage.
119+
120+
#### Scenario: Unclassifiable input creates triage item
121+
- **WHEN** user enters "remember to call mom" in chat (no command, unclear type)
122+
- **AND** AI cannot determine object type with confidence
123+
- **THEN** a Draft with `entity_type=UNKNOWN` is created
124+
- **AND** AI responds: "I'm not sure what type of item this should be. I've added it to your triage queue. Would you like to triage it now?"
125+
126+
#### Scenario: User accepts immediate triage
127+
- **WHEN** user responds "yes" to the triage offer
128+
- **THEN** the system starts triage mode with the new item first
129+
130+
#### Scenario: User defers triage
131+
- **WHEN** user responds "no" or continues with other input
132+
- **THEN** the item remains in the triage queue
133+
- **AND** the conversation continues normally
134+
135+
#### Scenario: Clear intent proceeds normally
136+
- **WHEN** user enters text with clear intent (e.g., "I need to send the report to Sarah by Friday")
137+
- **THEN** AI proceeds with normal creation flow (e.g., suggests `/commit`)
138+
- **AND** no triage item is created

0 commit comments

Comments
 (0)