bigwolfe commited on
Commit
31b3b17
·
1 Parent(s): ffcd038
specs/003-chatgpt-app-integration/checklists/requirements.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Specification Quality Checklist: ChatGPT App Integration
2
+
3
+ **Purpose**: Validate specification completeness and quality before proceeding to planning
4
+ **Created**: 2025-11-26
5
+ **Feature**: [spec.md](../spec.md)
6
+
7
+ ## Content Quality
8
+
9
+ - [x] No implementation details (languages, frameworks, APIs)
10
+ - [x] Focused on user value and business needs
11
+ - [x] Written for non-technical stakeholders
12
+ - [x] All mandatory sections completed
13
+
14
+ ## Requirement Completeness
15
+
16
+ - [x] No [NEEDS CLARIFICATION] markers remain
17
+ - [x] Requirements are testable and unambiguous
18
+ - [x] Success criteria are measurable
19
+ - [x] Success criteria are technology-agnostic (no implementation details)
20
+ - [x] All acceptance scenarios are defined
21
+ - [x] Edge cases are identified
22
+ - [x] Scope is clearly bounded
23
+ - [x] Dependencies and assumptions identified
24
+
25
+ ## Feature Readiness
26
+
27
+ - [x] All functional requirements have clear acceptance criteria
28
+ - [x] User scenarios cover primary flows
29
+ - [x] Feature meets measurable outcomes defined in Success Criteria
30
+ - [x] No implementation details leak into specification
31
+
32
+ ## Notes
33
+
34
+ - Spec is solid. It clearly delineates the scope (Widget vs App) and addresses the key integration points (Auth, Metadata) identified in the investigation.
specs/003-chatgpt-app-integration/data-model.md ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Data Model: ChatGPT Integration
2
+
3
+ ## Auth Entities
4
+
5
+ ### ServiceTokenStrategy
6
+ Strategy for validating static service tokens.
7
+
8
+ | Field | Type | Description |
9
+ |-------|------|-------------|
10
+ | `token` | `str` | The static token to match against. |
11
+ | `user_id` | `str` | The user ID to impersonate (e.g. "demo-user"). |
12
+
13
+ ## Configuration
14
+
15
+ ### AppConfig Updates
16
+ New fields added to `AppConfig`.
17
+
18
+ | Field | Type | Description |
19
+ |-------|------|-------------|
20
+ | `chatgpt_service_token` | `Optional[str]` | Static token for Apps SDK auth. |
21
+ | `chatgpt_cors_origin` | `str` | Allowed CORS origin (default: `https://chatgpt.com`). |
22
+
23
+ ## Tool Responses
24
+
25
+ ### WidgetMeta
26
+ Structure of the `_meta` field in `CallToolResult`.
27
+
28
+ ```json
29
+ {
30
+ "openai": {
31
+ "outputTemplate": "https://your-space.hf.space/widget",
32
+ "toolInvocation": {
33
+ "invoking": "Searching notes...",
34
+ "invoked": "Found 3 notes."
35
+ }
36
+ }
37
+ }
38
+ ```
specs/003-chatgpt-app-integration/plan.md ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Implementation Plan: [FEATURE]
2
+
3
+ **Branch**: `[###-feature-name]` | **Date**: [DATE] | **Spec**: [link]
4
+ **Input**: Feature specification from `/specs/[###-feature-name]/spec.md`
5
+
6
+ **Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow.
7
+
8
+ ## Summary
9
+
10
+ [Extract from feature spec: primary requirement + technical approach from research]
11
+
12
+ ## Technical Context
13
+
14
+ <!--
15
+ ACTION REQUIRED: Replace the content in this section with the technical details
16
+ for the project. The structure here is presented in advisory capacity to guide
17
+ the iteration process.
18
+ -->
19
+
20
+ **Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]
21
+ **Primary Dependencies**: [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION]
22
+ **Storage**: [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
23
+ **Testing**: [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION]
24
+ **Target Platform**: [e.g., Linux server, iOS 15+, WASM or NEEDS CLARIFICATION]
25
+ **Project Type**: [single/web/mobile - determines source structure]
26
+ **Performance Goals**: [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION]
27
+ **Constraints**: [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION]
28
+ **Scale/Scope**: [domain-specific, e.g., 10k users, 1M LOC, 50 screens or NEEDS CLARIFICATION]
29
+
30
+ ## Constitution Check
31
+
32
+ *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
33
+
34
+ [Gates determined based on constitution file]
35
+
36
+ ## Project Structure
37
+
38
+ ### Documentation (this feature)
39
+
40
+ ```text
41
+ specs/[###-feature]/
42
+ ├── plan.md # This file (/speckit.plan command output)
43
+ ├── research.md # Phase 0 output (/speckit.plan command)
44
+ ├── data-model.md # Phase 1 output (/speckit.plan command)
45
+ ├── quickstart.md # Phase 1 output (/speckit.plan command)
46
+ ├── contracts/ # Phase 1 output (/speckit.plan command)
47
+ └── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan)
48
+ ```
49
+
50
+ ### Source Code (repository root)
51
+ <!--
52
+ ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
53
+ for this feature. Delete unused options and expand the chosen structure with
54
+ real paths (e.g., apps/admin, packages/something). The delivered plan must
55
+ not include Option labels.
56
+ -->
57
+
58
+ ```text
59
+ # [REMOVE IF UNUSED] Option 1: Single project (DEFAULT)
60
+ src/
61
+ ├── models/
62
+ ├── services/
63
+ ├── cli/
64
+ └── lib/
65
+
66
+ tests/
67
+ ├── contract/
68
+ ├── integration/
69
+ └── unit/
70
+
71
+ # [REMOVE IF UNUSED] Option 2: Web application (when "frontend" + "backend" detected)
72
+ backend/
73
+ ├── src/
74
+ │ ├── models/
75
+ │ ├── services/
76
+ │ └── api/
77
+ └── tests/
78
+
79
+ frontend/
80
+ ├── src/
81
+ │ ├── components/
82
+ │ ├── pages/
83
+ │ └── services/
84
+ └── tests/
85
+
86
+ # [REMOVE IF UNUSED] Option 3: Mobile + API (when "iOS/Android" detected)
87
+ api/
88
+ └── [same as backend above]
89
+
90
+ ios/ or android/
91
+ └── [platform-specific structure: feature modules, UI flows, platform tests]
92
+ ```
93
+
94
+ **Structure Decision**: [Document the selected structure and reference the real
95
+ directories captured above]
96
+
97
+ ## Complexity Tracking
98
+
99
+ > **Fill ONLY if Constitution Check has violations that must be justified**
100
+
101
+ | Violation | Why Needed | Simpler Alternative Rejected Because |
102
+ |-----------|------------|-------------------------------------|
103
+ | [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
104
+ | [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |
specs/003-chatgpt-app-integration/research.md ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Phase 0: Research & Technical Decisions
2
+
3
+ ## 1. FastMCP Metadata Injection
4
+
5
+ **Decision**: Return `CallToolResult` with `_meta` for UI tools.
6
+
7
+ **Strategy**:
8
+ - We will stop returning pure Pydantic models from tools that need to trigger widgets (`read_note`, `search_notes`).
9
+ - Instead, these tools will instantiate the Pydantic model, dump it to a dictionary, and wrap it in a `CallToolResult` object.
10
+ - The `_meta` field will contain `openai: { outputTemplate: "..." }`.
11
+ - Non-UI tools (e.g., `list_notes`, `delete_note`) will continue to return Pydantic models or simple text to keep them lightweight.
12
+
13
+ **Rationale**: This aligns with the OpenAI Apps SDK pattern and allows us to trigger widgets without breaking the existing schema validation (since `structuredContent` will still match the Pydantic schema).
14
+
15
+ ## 2. React Widget Strategy
16
+
17
+ **Decision**: Use a separate Vite entry point (`widget.html` + `widget.tsx`).
18
+
19
+ **Strategy**:
20
+ - Create `frontend/widget.html` as a lightweight entry point.
21
+ - Create `frontend/src/widget.tsx` to render the widget application.
22
+ - Refactor `NoteViewer.tsx` into a "pure" component (if it isn't already) that can be imported by both `App.tsx` and `widget.tsx`.
23
+ - Use `vite-plugin-html` or manual rollup config to output multiple HTML files.
24
+
25
+ **Rationale**:
26
+ - **Isolation**: Prevents the main app's router, sidebar, and heavy layout styles from leaking into the iframe.
27
+ - **Performance**: The widget bundle will be smaller.
28
+ - **Simplicity**: Easier to reason about "widget state" when it's a fresh React mount rather than a route transition in a complex SPA.
29
+
30
+ ## 3. Authentication
31
+
32
+ **Decision**: Use a configurable "Service Token" strategy.
33
+
34
+ **Strategy**:
35
+ - Refactor `AuthService` to support a `TokenValidator` interface or strategy.
36
+ - Implement `JWTValidator` (existing) and `StaticTokenValidator` (new).
37
+ - Add `CHATGPT_SERVICE_TOKEN` to `AppConfig`.
38
+ - If `CHATGPT_SERVICE_TOKEN` is set, the backend will accept it as a valid Bearer token for any user context (or a specific "chatgpt-bot" user).
39
+
40
+ **Rationale**:
41
+ - Hugging Face OAuth is not compatible with the Apps SDK OIDC flow.
42
+ - Implementing a full OIDC provider is out of scope for the hackathon.
43
+ - A static service token is secure enough for a demo/hackathon submission and easy to configure in the OpenAI Developer Platform.
44
+
45
+ ## 4. Infrastructure & Hosting
46
+
47
+ **Decision**: Serve `widget.html` via FastAPI static mount with Skybridge MIME type.
48
+
49
+ **Strategy**:
50
+ - Update `backend/src/api/main.py` to serve `frontend/dist/widget.html` on a specific route (e.g., `/widget`).
51
+ - Ensure the Content-Type header is `text/html+skybridge` (or whatever the specific requirement is, usually just serving it is enough, but we will double-check if OpenAI needs specific headers). *Correction: The expert mentioned `text/html+skybridge` media type for `FileResponse`.*
52
+ - Update CORS to allow `https://chatgpt.com` (and `https://*.chatgpt.com`).
53
+
54
+ **Rationale**: Required for the widget to load inside the ChatGPT iframe.
specs/003-chatgpt-app-integration/spec.md ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Feature Specification: ChatGPT App Integration
2
+
3
+ **Feature**: 003-chatgpt-app-integration
4
+ **Status**: Draft
5
+ **Created**: 2025-11-26
6
+
7
+ ## 1. Summary
8
+
9
+ Transform the Document-MCP project into a "ChatGPT App" compatible with the OpenAI Apps SDK. This integration enables ChatGPT users to interact with their document vault using native-feeling UI widgets (Note Viewer, Search Results) embedded directly in the chat interface, powered by the existing FastMCP server.
10
+
11
+ ## 2. Problem Statement
12
+
13
+ **Context**: Currently, the Document-MCP project works as a standalone web app or a standard MCP server.
14
+ **Problem**: ChatGPT users accessing the vault via standard MCP tools receive raw markdown text in the chat stream, which is verbose and lacks interactivity. They cannot easily visualize the vault or navigate links without leaving the chat context.
15
+ **Impact**: Limits the "AI Knowledge Assistant" experience by forcing users to context-switch between ChatGPT and a separate tab, or suffer through poor readability of raw text responses.
16
+
17
+ ## 3. Goals & Non-Goals
18
+
19
+ ### Goals
20
+ - **Seamless Integration**: Enable users to search, view, and edit notes entirely within the ChatGPT interface.
21
+ - **Visual Widgets**: Replace raw text responses with interactive UI widgets for:
22
+ - Note Viewing (with Markdown rendering and Wikilink support)
23
+ - Search Results (clean list with snippets)
24
+ - **Dual-Mode Operation**: Ensure the application continues to function as a standalone web app and standard MCP server while supporting the ChatGPT App mode.
25
+ - **Hackathon Readiness**: Prioritize a functional "demo user" or "service token" auth flow to ensure valid submission for the "Best ChatGPT App" category.
26
+
27
+ ### Non-Goals
28
+ - **Full Obsidian UI in Chat**: We will not iframe the entire application (sidebar, graph view, settings) into ChatGPT.
29
+ - **Production OAuth**: We will not implement a full OIDC provider for multi-tenant public access at this stage; a simplified auth strategy is sufficient for the hackathon.
30
+ - **Complex Graph Viz**: The Graph View widget is out of scope for the initial V1 integration.
31
+
32
+ ## 4. User Scenarios
33
+
34
+ ### Scenario 1: The Recall Loop
35
+ **User**: A developer brainstorming in ChatGPT.
36
+ **Action**: User asks, "What did I note about the authentication API?"
37
+ **System**: ChatGPT calls `search_notes("authentication API")`.
38
+ **Result**: Instead of a JSON dump, a **Search Results Widget** appears in the chat, listing matching notes. The user clicks "API Documentation" in the widget.
39
+ **Follow-up**: The widget transitions to a **Note Viewer Widget**, displaying the rendered markdown of "API Documentation".
40
+
41
+ ### Scenario 2: In-Context Editing
42
+ **User**: Reading the "API Documentation" note in the widget.
43
+ **Action**: User tells ChatGPT, "Update the Auth section to mention we use RS256 now."
44
+ **System**: ChatGPT calls `read_note` (invisible to user), generates the diff, calls `write_note`, and confirms.
45
+ **Result**: The Note Viewer widget refreshes (or a status widget appears) showing the updated content directly in the thread.
46
+
47
+ ## 5. Functional Requirements
48
+
49
+ ### 5.1 Backend & MCP
50
+ - **Metadata Injection**: The `read_note` and `search_notes` tools must return a `CallToolResult` containing the `_meta.openai.outputTemplate` field to trigger widgets.
51
+ - **CORS**: The API must allow requests from `https://chatgpt.com` to support iframe loading.
52
+ - **Service Token**: The backend must support a configured `CHATGPT_SERVICE_TOKEN` to allow the OpenAI Apps SDK to authenticate without full user-facing OAuth.
53
+
54
+ ### 5.2 Frontend Widgets
55
+ - **Widget Entry Point**: A new build target (`widget.html` + `widget.tsx`) must be created to serve simplified UI components.
56
+ - **Note Viewer Widget**: A lightweight version of the `NoteViewer` component that:
57
+ - Renders Markdown.
58
+ - Handles Wikilink clicks (by requesting ChatGPT to navigate or loading the new note within the widget).
59
+ - Hides the sidebar and app chrome.
60
+ - **Search Widget**: A simple list view for search results that triggers note navigation on click.
61
+
62
+ ### 5.3 Infrastructure
63
+ - **Static Serving**: The FastAPI server must serve `widget.html` with the correct `text/html+skybridge` MIME type when requested.
64
+ - **Build Pipeline**: The Vite configuration must output both the main SPA (`index.html`) and the widget bundle (`widget.html`).
65
+
66
+ ## 6. Success Criteria
67
+
68
+ 1. **Widget Rendering**: A `read_note` tool call successfully renders the custom HTML widget inside the ChatGPT Developer Mode interface.
69
+ 2. **Navigation**: Clicking a Wikilink in the widget successfully loads the target note (either by refreshing the widget or triggering a new tool call).
70
+ 3. **Zero Regression**: The existing standalone web app (`/`) continues to function normally for local development.
71
+ 4. **Performance**: Widget load time < 500ms (leveraging the lightweight bundle).
72
+
73
+ ## 7. Assumptions & Dependencies
74
+
75
+ - **Host**: Hugging Face Spaces or Localhost (tunneled) will be used for hosting.
76
+ - **Apps SDK**: We rely on the OpenAI Apps SDK beta features; behavior may be subject to platform changes.
77
+ - **Auth**: We assume a single-tenant or shared-tenant "demo" mode is acceptable for the hackathon submission.
78
+
79
+ ## 8. Questions & Clarifications
80
+
81
+ 1. **Widget Navigation**: When a user clicks a link in the widget, should it trigger a client-side router push (staying in the same iframe) or ask ChatGPT to "open note X"?
82
+ * *Assumption*: Client-side navigation within the widget is smoother for "browsing", while asking ChatGPT is better for "contextualizing". We will prioritize **client-side navigation** for V1 to keep the UI snappy.
83
+
84
+ 2. **Auth Header**: Will ChatGPT send the service token in the `Authorization` header?
85
+ * *Assumption*: Yes, we will configure the Custom API Action or App definition with the static Bearer token.