prompt_objects 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/CLAUDE.md +113 -44
  4. data/README.md +140 -14
  5. data/frontend/index.html +5 -1
  6. data/frontend/src/App.tsx +72 -79
  7. data/frontend/src/canvas/CanvasView.tsx +5 -5
  8. data/frontend/src/canvas/constants.ts +31 -31
  9. data/frontend/src/canvas/inspector/InspectorPanel.tsx +4 -4
  10. data/frontend/src/canvas/inspector/POInspector.tsx +35 -35
  11. data/frontend/src/canvas/inspector/ToolCallInspector.tsx +13 -13
  12. data/frontend/src/canvas/nodes/PONode.ts +2 -2
  13. data/frontend/src/components/ContextMenu.tsx +5 -4
  14. data/frontend/src/components/EnvDataPane.tsx +69 -0
  15. data/frontend/src/components/Inspector.tsx +263 -0
  16. data/frontend/src/components/MarkdownMessage.tsx +22 -20
  17. data/frontend/src/components/MethodList.tsx +90 -0
  18. data/frontend/src/components/ModelSelector.tsx +13 -14
  19. data/frontend/src/components/NotificationPanel.tsx +29 -33
  20. data/frontend/src/components/ObjectList.tsx +78 -0
  21. data/frontend/src/components/PaneSlot.tsx +30 -0
  22. data/frontend/src/components/SourcePane.tsx +202 -0
  23. data/frontend/src/components/SystemBar.tsx +74 -0
  24. data/frontend/src/components/Transcript.tsx +76 -0
  25. data/frontend/src/components/UsagePanel.tsx +27 -27
  26. data/frontend/src/components/Workspace.tsx +260 -0
  27. data/frontend/src/components/index.ts +10 -9
  28. data/frontend/src/hooks/useResize.ts +55 -0
  29. data/frontend/src/hooks/useWebSocket.ts +70 -0
  30. data/frontend/src/index.css +27 -10
  31. data/frontend/src/store/index.ts +36 -0
  32. data/frontend/src/types/index.ts +13 -0
  33. data/frontend/tailwind.config.js +28 -9
  34. data/lib/prompt_objects/capability.rb +23 -1
  35. data/lib/prompt_objects/connectors/mcp.rb +2 -16
  36. data/lib/prompt_objects/environment.rb +15 -0
  37. data/lib/prompt_objects/llm/openai_adapter.rb +22 -0
  38. data/lib/prompt_objects/mcp/tools/inspect_po.rb +1 -31
  39. data/lib/prompt_objects/mcp/tools/list_prompt_objects.rb +1 -6
  40. data/lib/prompt_objects/prompt_object.rb +239 -7
  41. data/lib/prompt_objects/server/api/routes.rb +16 -48
  42. data/lib/prompt_objects/server/app.rb +14 -0
  43. data/lib/prompt_objects/server/public/assets/{index-xvyeb-5Z.js → index-DEPawnfZ.js} +206 -206
  44. data/lib/prompt_objects/server/public/assets/index-oMrRce1m.css +1 -0
  45. data/lib/prompt_objects/server/public/index.html +7 -3
  46. data/lib/prompt_objects/server/websocket_handler.rb +41 -98
  47. data/lib/prompt_objects/server.rb +6 -62
  48. data/lib/prompt_objects/session/store.rb +176 -4
  49. data/lib/prompt_objects/universal/delete_env_data.rb +70 -0
  50. data/lib/prompt_objects/universal/get_env_data.rb +64 -0
  51. data/lib/prompt_objects/universal/list_env_data.rb +61 -0
  52. data/lib/prompt_objects/universal/store_env_data.rb +87 -0
  53. data/lib/prompt_objects/universal/update_env_data.rb +88 -0
  54. data/lib/prompt_objects.rb +6 -1
  55. data/prompt_objects.gemspec +1 -1
  56. data/templates/arc-agi-1/objects/observer.md +4 -0
  57. data/templates/arc-agi-1/objects/solver.md +10 -1
  58. data/templates/arc-agi-1/objects/verifier.md +4 -0
  59. data/templates/arc-agi-1/primitives/find_objects.rb +1 -1
  60. data/templates/arc-agi-1/primitives/grid_diff.rb +2 -2
  61. data/templates/arc-agi-1/primitives/grid_info.rb +1 -1
  62. data/templates/arc-agi-1/primitives/grid_transform.rb +1 -1
  63. data/templates/arc-agi-1/primitives/render_grid.rb +1 -0
  64. data/templates/arc-agi-1/primitives/test_solution.rb +3 -0
  65. data/tools/thread-explorer.html +27 -0
  66. metadata +18 -16
  67. data/Gemfile.lock +0 -233
  68. data/IMPLEMENTATION_PLAN.md +0 -1073
  69. data/design-doc-v2.md +0 -1232
  70. data/frontend/src/components/CapabilitiesPanel.tsx +0 -141
  71. data/frontend/src/components/ChatPanel.tsx +0 -296
  72. data/frontend/src/components/Dashboard.tsx +0 -83
  73. data/frontend/src/components/Header.tsx +0 -153
  74. data/frontend/src/components/MessageBus.tsx +0 -56
  75. data/frontend/src/components/POCard.tsx +0 -56
  76. data/frontend/src/components/PODetail.tsx +0 -124
  77. data/frontend/src/components/PromptPanel.tsx +0 -156
  78. data/frontend/src/components/SessionsPanel.tsx +0 -174
  79. data/frontend/src/components/ThreadsSidebar.tsx +0 -163
  80. data/lib/prompt_objects/server/public/assets/index-6y64NXFy.css +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92cf8b8492d42dee0adb37a4fb41692e6b228ab7a364f9176444c60cd81eb63d
4
- data.tar.gz: 45e8828d53f7b9c4893fb6374535bbb099c77e92371a3e111bda07d9e35db93e
3
+ metadata.gz: 1e9bb13a5f2b407279723343fe43ce570119e64a3fe2a115e4f427d195ec7040
4
+ data.tar.gz: fc1300754c1774ec388928752b84dd8a60286659904b8b72053fde457842ea71
5
5
  SHA512:
6
- metadata.gz: 123244bee715f744b7b377bbf4e2912ed28cbb966ce6b92bb7d43a5ea053bf2460e7bb10c35acf09ab5f4cfa8f0afeeb78198be62acfbde44b86f3c5f0559deb
7
- data.tar.gz: 15ee859102e87e971df1e38b756d776a0f913148554974fc2fe9ae79b12853cf9028793aadfaabb92aa1d74961739c97a51c258c0e9e2a38cbf77fb5f931b46d
6
+ metadata.gz: 56e4a427b43b49fc7520f9268a3e31c4a81d39c50ad0329985ab9d678631a2a88c41d070a7e13d97c01e2328de56e917d59b2b06c078fef9174a5a7fdc5db87b
7
+ data.tar.gz: a6bb7914d1b58c8c445deae870c2a06c004b9e7604b72107574f89c7ea9da2b8172034c358078b920d52b57eefe24acb68668d7057f16e61ed2e62ee2a85ca95
data/CHANGELOG.md CHANGED
@@ -2,6 +2,39 @@
2
2
 
3
3
  All notable changes to PromptObjects are documented in this file.
4
4
 
5
+ ## [0.6.0] - 2026-02-17
6
+
7
+ ### Added
8
+
9
+ - **Shared environment data** — 5 new universal capabilities (`store_env_data`, `get_env_data`, `list_env_data`, `update_env_data`, `delete_env_data`) provide a thread-scoped key-value store for delegation chains. Data is scoped to the root thread so separate conversations stay isolated. Entries include a `short_description` for lightweight LLM discovery without fetching full values.
10
+ - **Live environment data pane** — New collapsible pane in the Inspector shows shared env data updating in real-time as POs store and modify entries during delegation chains. WebSocket broadcasting (`env_data_changed`, `env_data_list`), a REST endpoint (`GET /api/sessions/:id/env_data`), and env data rendering in the Thread Explorer.
11
+ - **Delegation context** — POs now receive context about their delegation chain. An expanded system prompt teaches POs about their nature, a delegation preamble prepends caller context to delegated messages, and the full delegation chain is built from thread lineage.
12
+ - **Capability guard** — `execute_tool_calls` now rejects tools not in a PO's allowed set (declared capabilities + universals). Previously the LLM could hallucinate calls to any registered tool and they would execute. Now it receives an error directing it to use `add_capability` first.
13
+ - **Env data in thread exports** — `serialize_tree_for_export` includes env data entries at the root level of exported thread trees. Thread Explorer renders these in an amber-colored section.
14
+
15
+ ### Fixed
16
+
17
+ - **Root font-size causing undersized text** — Removed a `font-size: 14px` on the root `html` element that made all rem-based Tailwind sizes ~12% smaller than intended (e.g. `text-xs` computed to 10.5px instead of 12px).
18
+ - **Invisible resize handle boundaries** — Added border styling to horizontal and vertical resize handles so pane boundaries are visible without hovering.
19
+ - **Stale MCP tools tests** — Fixed test expectations broken by PO serialization centralization in 0.5.0.
20
+
21
+ ## [0.5.0] - 2026-02-13
22
+
23
+ ### Added
24
+
25
+ - **Smalltalk System Browser redesign** — Complete frontend overhaul replacing the chat-app UI with a multi-pane object browser. POs are treated as live objects in a running image: permanent ObjectList (left pane), multi-pane Inspector with MethodList + SourcePane, REPL-style Workspace, and bottom Transcript. Warm charcoal + amber palette with Geist fonts. All panels resizable via drag handles.
26
+ - **Collapsible inspector top pane** — The Methods + Source pane has a thin header bar with a collapse/expand toggle. When collapsed, the Workspace fills the full inspector height. Collapse state persists across PO switches.
27
+ - **Source entry in method list** — A "Source" entry at the top of the method list provides a clear way to navigate back to the PO's prompt after inspecting a capability.
28
+ - **Dynamic Ollama model discovery** — LLM config now queries the Ollama API for installed models instead of using a static list.
29
+
30
+ ### Fixed
31
+
32
+ - **Capabilities disappearing on file save** — `po_modified` events were sending capabilities as plain string names instead of rich objects, overwriting the store. All serialization paths now emit consistent `{name, description, parameters}` objects.
33
+ - **Centralized PO serialization** — Moved duplicated state/message/session serialization from WebSocketHandler and API routes into `PromptObject` (`to_state_hash`, `to_summary_hash`, `to_inspect_hash`). Eliminates inconsistent serialization as a class of bug.
34
+ - **Missing items field in array tool schemas** — LLM APIs reject array parameters without an `items` field. Added a defensive sanitizer in `Capability#descriptor` as a fallback.
35
+ - **OpenAI adapter error details** — 4xx errors from Ollama now surface the actual rejection reason instead of just "status 400".
36
+ - **All WebSocket message types handled** — Added frontend handlers for `prompt_updated`, `llm_error`, `session_created`, and `session_switched`. Removed defensive normalization workarounds.
37
+
5
38
  ## [0.4.0] - 2026-02-11
6
39
 
7
40
  ### Added
data/CLAUDE.md CHANGED
@@ -6,17 +6,21 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
6
6
 
7
7
  **PromptObjects** is a Ruby framework where markdown files with LLM-backed behavior act as first-class autonomous entities. The core insight: **everything is a capability**—primitives (Ruby code) and Prompt-Objects (markdown files) share the same interface, differing only in interpretation complexity.
8
8
 
9
- **Current Status**: Design phase—`design-doc-v2.md` contains the full specification, `IMPLEMENTATION_PLAN.md` has detailed phased build plans. No implementation code exists yet.
9
+ **Current Status**: v0.5.0 — The core framework is fully implemented and functional. The original 6-phase implementation plan is complete. Active development is focused on visualization, developer experience, and exploring new primitives. See `CHANGELOG.md` for release history and `docs/archive/` for original design context.
10
10
 
11
11
  ## Architecture
12
12
 
13
13
  ```
14
- ENVIRONMENT
14
+ RUNTIME (Environment)
15
15
  ├── CAPABILITY REGISTRY
16
16
  │ ├── PRIMITIVES (Ruby) - deterministic interpretation
17
- └── PROMPT-OBJECTS (Markdown) - semantic interpretation via LLM
18
- ├── MESSAGE BUS - routes messages, logs for visualization
19
- └── TERMINAL UI (Charm) - capability bar, message log, conversation, input
17
+ ├── PROMPT-OBJECTS (Markdown) - semantic interpretation via LLM
18
+ │ └── UNIVERSAL CAPABILITIES - available to all POs automatically
19
+ ├── MESSAGE BUS - routes messages, logs to SQLite for replay
20
+ ├── SESSION STORE (SQLite) - persistent conversation threads, delegation tracking
21
+ ├── HUMAN QUEUE - non-blocking ask_human requests
22
+ ├── WEB SERVER (Falcon + async-websocket) - serves React frontend
23
+ └── MCP SERVER - exposes POs as tools via Model Context Protocol
20
24
  ```
21
25
 
22
26
  ### Unified Capability Interface
@@ -53,56 +57,121 @@ You are a careful, thoughtful file reader...
53
57
  Available to all Prompt-Objects automatically (no frontmatter declaration needed):
54
58
  - `ask_human` - pause for human input/confirmation
55
59
  - `think` - internal reasoning (not shown to human)
56
- - `request_capability` - ask environment for new capability
60
+ - `create_capability` / `add_capability` / `remove_capability` - self-modification
61
+ - `list_capabilities` / `list_primitives` - introspection
62
+ - `create_primitive` / `add_primitive` / `delete_primitive` / `verify_primitive` / `modify_primitive` / `request_primitive` - primitive management
63
+ - `modify_prompt` - rewrite own system prompt at runtime
64
+ - `store_env_data` / `get_env_data` / `list_env_data` / `update_env_data` / `delete_env_data` - thread-scoped shared key-value store for delegation chains
57
65
 
58
- ## Technology Stack
59
-
60
- - **Ruby** - core implementation
61
- - **LLM APIs** - OpenAI, Anthropic, Gemini (adapter pattern)
62
- - **Charm** - Terminal UI (Bubble Tea for interaction, Lipgloss for styling, Glamour for markdown)
63
- - **MCP** - Model Context Protocol integration
66
+ ### PO-to-PO Delegation
67
+ When a PO calls another PO, the system creates an isolated delegation thread in the target PO. The caller's context is tracked so messages show correct provenance. Delegation start/complete events are broadcast via WebSocket for real-time UI updates.
64
68
 
65
- ### TUI Architecture Note
69
+ ## Technology Stack
66
70
 
67
- The TUI uses a **single Bubble Tea program** with internal screen states (picker, wizard, main). Do NOT run multiple sequential `Bubbletea.run` calls—this causes terminal state corruption. See `docs/phase-8-environments.md` for details.
71
+ - **Ruby** (>= 3.2, tested through Ruby 4) - core implementation
72
+ - **LLM APIs** - OpenAI, Anthropic, Gemini, Ollama, OpenRouter (adapter pattern via `LLM::Factory`)
73
+ - **Falcon** - async HTTP server for REST API and static file serving
74
+ - **async-websocket** - real-time WebSocket communication
75
+ - **React + TypeScript** - web frontend (Smalltalk System Browser-inspired multi-pane UI)
76
+ - **Three.js** - spatial canvas visualization (force-directed PO graph)
77
+ - **SQLite** - session persistence and event log storage
78
+ - **MCP** - Model Context Protocol server mode
68
79
 
69
- ## Planned File Structure
80
+ ## File Structure
70
81
 
71
82
  ```
72
83
  prompt_objects/
73
- ├── exe/prompt_objects # CLI entrypoint
84
+ ├── exe/prompt_objects # CLI entrypoint
74
85
  ├── lib/
75
- │ ├── prompt_objects.rb # Main entry
86
+ │ ├── prompt_objects.rb # Main entry, requires all modules
76
87
  │ └── prompt_objects/
77
- │ ├── environment.rb # Runtime container
78
- │ ├── capability.rb # Base interface
79
- │ ├── prompt_object.rb # PO implementation
80
- │ ├── primitive.rb # Primitive tool wrapper
81
- │ ├── loader.rb # Parses frontmatter + body
82
- │ ├── registry.rb # Capability registration
83
- │ ├── message_bus.rb # Message routing and logging
84
- │ ├── llm/ # LLM adapters
85
- │ ├── primitives/ # Built-in primitives (read_file, etc.)
86
- │ ├── universal/ # Universal capabilities
87
- │ ├── mcp/ # MCP integration
88
- └── ui/ # Charm-based terminal UI
89
- ├── objects/ # Where Prompt-Objects live (.md files)
90
- └── primitives/ # Optional user-defined primitives
88
+ │ ├── environment.rb # Runtime container (registry, bus, LLM, sessions)
89
+ │ ├── capability.rb # Base capability interface
90
+ │ ├── prompt_object.rb # PO implementation (LLM conversation loop)
91
+ │ ├── primitive.rb # Primitive tool wrapper
92
+ │ ├── loader.rb # Parses frontmatter + body from .md files
93
+ │ ├── registry.rb # Capability registration and lookup
94
+ │ ├── message_bus.rb # Message routing, logging, SQLite persistence
95
+ │ ├── human_queue.rb # Non-blocking human interaction queue
96
+ │ ├── cli.rb # CLI command definitions
97
+ │ ├── server.rb # Web server setup
98
+ │ ├── server/
99
+ │ ├── app.rb # Sinatra application
100
+ │ │ ├── api/routes.rb # REST API endpoints
101
+ │ │ ├── websocket_handler.rb # WebSocket event handling
102
+ │ │ └── file_watcher.rb # Live .md file change detection
103
+ │ ├── llm/
104
+ │ │ ├── factory.rb # Provider/model selection
105
+ │ │ ├── response.rb # Unified response object
106
+ │ │ ├── pricing.rb # Token cost calculation
107
+ │ │ ├── openai_adapter.rb # OpenAI + Ollama + OpenRouter
108
+ │ │ ├── anthropic_adapter.rb
109
+ │ │ └── gemini_adapter.rb
110
+ │ ├── primitives/ # Built-in: read_file, list_files, write_file, http_get
111
+ │ ├── universal/ # 14 universal capabilities (see list above)
112
+ │ ├── connectors/ # Interface adapters (base, mcp)
113
+ │ ├── mcp/ # MCP server and tool definitions
114
+ │ ├── session/
115
+ │ │ └── store.rb # SQLite session/thread persistence
116
+ │ └── environment/
117
+ │ ├── manager.rb # Create/list/clone environments
118
+ │ ├── manifest.rb # Environment metadata (manifest.yml)
119
+ │ ├── git.rb # Auto-commit integration
120
+ │ ├── exporter.rb # Environment export
121
+ │ └── importer.rb # Environment import
122
+ ├── frontend/ # React + TypeScript web UI
123
+ │ └── src/
124
+ │ ├── App.tsx
125
+ │ ├── components/ # SystemBar, ObjectList, Inspector, Workspace, Transcript
126
+ │ ├── canvas/ # Three.js spatial visualization
127
+ │ ├── hooks/ # WebSocket, state management hooks
128
+ │ ├── store/ # Frontend state
129
+ │ └── types/ # TypeScript type definitions
130
+ ├── objects/ # Default POs: greeter, reader, coordinator
131
+ ├── templates/ # Environment templates (basic, developer, writer, arc-agi-1, etc.)
132
+ ├── tools/ # Development tooling
133
+ └── test/ # Unit and integration tests
91
134
  ```
92
135
 
93
- ## Implementation Phases
94
-
95
- 1. **Core Loop**: Capability base, PromptObject, Loader, single LLM adapter, simple REPL
96
- 2. **Primitives & Binding**: Primitive base, built-in primitives, Registry
97
- 3. **Multi-Capability**: Message bus with logging, PO↔PO communication
98
- 4. **Self-Modification**: Universal capabilities including create_capability
99
- 5. **Polish & UI**: Full Charm integration, all UI components
100
- 6. **Demo Ready**: Error handling, testing, practice runs
101
-
102
136
  ## Key Concepts
103
137
 
104
138
  - **Semantic Binding**: Natural language → capability call (visible in message log)
105
- - **PO↔PO Communication**: Prompt-Objects can call each other as capabilities
106
- - **Self-Modification**: System can create new Prompt-Objects at runtime (with human approval)
107
- - **Human-in-the-Loop**: POs ask for confirmation on dangerous actions, clarification when ambiguous
108
- - **Non-blocking Human Queue**: When POs need human input (`ask_human`), they suspend (via Fibers) and queue a notification. Multiple POs can wait simultaneously. Human responds via notification panel, PO resumes automatically.
139
+ - **PO↔PO Communication**: Prompt-Objects call each other as capabilities through isolated delegation threads
140
+ - **Self-Modification**: POs can create new POs and primitives at runtime (with human approval)
141
+ - **Human-in-the-Loop**: POs use `ask_human` to pause and queue notifications; human responds asynchronously via the web UI
142
+ - **Environments**: Isolated collections of POs with their own sessions, git history, and configuration. Created from templates via CLI.
143
+ - **Thread Export**: Conversation threads (including delegation chains) exportable as Markdown or JSON
144
+
145
+ ## Development
146
+
147
+ ```bash
148
+ # Install dependencies
149
+ bundle install
150
+ cd frontend && npm install && cd ..
151
+
152
+ # Run tests
153
+ bundle exec rake test
154
+
155
+ # Serve an environment with web UI
156
+ prompt_objects serve <env-name> --open
157
+
158
+ # Environment management
159
+ prompt_objects env create <name> --template basic
160
+ prompt_objects env list
161
+ prompt_objects env info <name>
162
+ ```
163
+
164
+ ## Releases
165
+
166
+ Always tag releases. Pushing a version tag triggers the Discord notification workflow (`.github/workflows/discord-release.yml`), which extracts the matching section from `CHANGELOG.md` and posts it.
167
+
168
+ ```bash
169
+ # 1. Update version in prompt_objects.gemspec
170
+ # 2. Add changelog entry under ## [X.Y.Z] - YYYY-MM-DD
171
+ # 3. Commit: "Release vX.Y.Z — short description"
172
+ # 4. Tag and push:
173
+ git tag vX.Y.Z
174
+ git push && git push origin vX.Y.Z
175
+ # 5. Publish gem:
176
+ gem build prompt_objects.gemspec && gem push prompt_objects-X.Y.Z.gem
177
+ ```
data/README.md CHANGED
@@ -27,8 +27,86 @@ A Ruby framework where:
27
27
  - **Markdown files** define autonomous entities (Prompt Objects)
28
28
  - **YAML frontmatter** declares capabilities and configuration
29
29
  - **Markdown body** becomes identity and behavior (the system prompt)
30
- - **Capabilities** are shared between primitives (Ruby) and Prompt Objects (markdown)
31
- - **Environments** isolate collections of objects with their own memory
30
+ - **Capabilities** are shared between primitives (Ruby) and Prompt Objects (markdown) -- everything is a capability
31
+ - **Environments** isolate collections of objects with their own memory, git history, and configuration
32
+ - **PO-to-PO delegation** lets objects call each other through isolated threads with full provenance tracking
33
+
34
+ ### Prompt Object structure
35
+
36
+ ```markdown
37
+ ---
38
+ name: reader
39
+ description: Helps people understand files
40
+ capabilities:
41
+ - read_file
42
+ - list_files
43
+ ---
44
+
45
+ # Reader
46
+ ## Identity
47
+ You are a careful, thoughtful file reader...
48
+ ```
49
+
50
+ ### Web UI
51
+
52
+ The web interface is modeled after the Smalltalk System Browser -- a multi-pane environment for inspecting and interacting with live objects:
53
+
54
+ - **ObjectList** -- permanent left pane listing all POs in the environment
55
+ - **Inspector** -- split into a MethodList (capabilities) and SourcePane (the prompt markdown or capability source)
56
+ - **Workspace** -- a REPL-style chat pane for sending messages to the selected PO
57
+ - **Transcript** -- bottom pane showing message bus events in real time
58
+
59
+ All panels are resizable. The inspector's top pane collapses so the Workspace can fill the full height when you just want to talk.
60
+
61
+ ### Spatial Canvas
62
+
63
+ Navigate to `/canvas` for a Three.js 2D visualization of your environment. POs appear as glowing hexagonal nodes in a force-directed layout. Tool calls show as diamonds. Message arcs animate with traveling particles. Delegation lights up the target PO with a cyan glow. Click any node to inspect it. Keyboard shortcuts: F to fit, Escape to deselect.
64
+
65
+ ### MCP Server mode
66
+
67
+ Run any environment as an MCP (Model Context Protocol) server for integration with Claude Desktop, Cursor, or any MCP-compatible client:
68
+
69
+ ```bash
70
+ prompt_objects serve my-assistant --mcp
71
+ ```
72
+
73
+ Add to your `claude_desktop_config.json`:
74
+
75
+ ```json
76
+ {
77
+ "mcpServers": {
78
+ "my-assistant": {
79
+ "command": "prompt_objects",
80
+ "args": ["serve", "--mcp", "my-assistant"]
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ Exposes tools for sending messages, listing POs, inspecting state, getting conversations, and responding to pending `ask_human` requests.
87
+
88
+ ### Multi-provider LLM support
89
+
90
+ Swap providers with an environment variable. Adapters for:
91
+
92
+ - **OpenAI** -- GPT-5.2, GPT-4.1, o3-mini, o1
93
+ - **Anthropic** -- Claude Haiku 4.5, Claude Sonnet 4.5, Claude Opus 4
94
+ - **Gemini** -- Gemini 3 Flash, Gemini 2.5 Pro, Gemini 2.5 Flash
95
+ - **Ollama** -- any locally installed model, discovered automatically
96
+ - **OpenRouter** -- access any model through a single API key
97
+
98
+ ### Thread Explorer
99
+
100
+ A standalone HTML visualizer for exported conversation threads. Open it from the CLI to browse delegation chains, message flow, and tool call sequences:
101
+
102
+ ```bash
103
+ prompt_objects explore my-env
104
+ prompt_objects explore my-env --session abc123
105
+ ```
106
+
107
+ ### Note on the TUI
108
+
109
+ A terminal UI (built with Charm libraries) exists in the codebase but is deprioritized. The web UI is the primary interface for day-to-day use.
32
110
 
33
111
  How
34
112
  ===
@@ -49,25 +127,73 @@ prompt_objects env create my-project --template basic
49
127
  prompt_objects serve my-project --open
50
128
  ```
51
129
 
52
- ### Environment Commands
130
+ ### Commands
53
131
 
54
- ```bash
55
- prompt_objects env list # List all environments
56
- prompt_objects env create <name> # Create new environment
57
- prompt_objects env info <name> # Show environment details
58
- prompt_objects env clone <src> <dst> # Clone an environment
132
+ ```
133
+ prompt_objects serve <env> Start web server (default)
134
+ prompt_objects serve <env> --open Start and open browser
135
+ prompt_objects serve <env> --mcp Start as MCP server
136
+ prompt_objects serve <env> --port 4000 Custom port (default: 3000)
137
+
138
+ prompt_objects repl [name] [objects_dir] Interactive REPL with a prompt object
139
+ prompt_objects repl --sandbox REPL in sandbox mode (isolates changes)
140
+
141
+ prompt_objects message <env> <po> "text" Send a message and print the response
142
+ prompt_objects message <env> <po> "text" --json JSON output
143
+ prompt_objects message <env> <po> "text" --events Include event log
144
+
145
+ prompt_objects events <env> Show recent message bus events
146
+ prompt_objects events <env> --session ID Events for a specific session
147
+ prompt_objects events <env> --json JSON output
148
+
149
+ prompt_objects explore [env] Open Thread Explorer in browser
150
+ prompt_objects explore <env> --session ID Visualize a specific thread
151
+ ```
152
+
153
+ ### Environment management
154
+
155
+ ```
156
+ prompt_objects env list List all environments
157
+ prompt_objects env create <name> Create new environment
158
+ prompt_objects env create <name> -t <tmpl> Create from template
159
+ prompt_objects env info <name> Show environment details
160
+ prompt_objects env clone <src> <dst> Clone an environment
161
+ prompt_objects env export <name> Export as .poenv bundle
162
+ prompt_objects env import <file.poenv> Import from bundle
163
+ prompt_objects env archive <name> Soft-delete (archive)
164
+ prompt_objects env restore <name> Restore archived environment
165
+ prompt_objects env delete <name> --permanent Permanently delete archived env
166
+ prompt_objects env default <name> Set the default environment
59
167
  ```
60
168
 
61
169
  ### Templates
62
170
 
63
- - `basic` - No capabilities, learns as needed (great for demos)
64
- - `minimal` - Basic assistant with file reading
65
- - `developer` - Code review, debugging, testing specialists
66
- - `writer` - Editor, researcher for content creation
171
+ Create an environment from a template with `prompt_objects env create <name> --template <template>`:
172
+
173
+ | Template | Description |
174
+ |---|---|
175
+ | `basic` | No capabilities, learns as needed -- great for demos |
176
+ | `minimal` | Basic assistant with file reading |
177
+ | `developer` | Code review, debugging, testing specialists |
178
+ | `writer` | Editor, researcher for content creation |
179
+ | `empty` | Start from scratch with just a bootstrap assistant |
180
+ | `arc-agi-1` | ARC-AGI-1 challenge solver with grid primitives |
67
181
 
68
182
  Extras
69
183
  ======
70
184
 
71
- - **License**: MIT
72
- - **Ruby**: >= 3.2.0
185
+ ### Community
186
+
187
+ Join the [Discord](https://discord.gg/fcMvcwdrZS) for support, discussion, and updates.
188
+
189
+ ### Blog Posts
190
+
191
+ - [What if we took message passing seriously?](https://worksonmymachine.ai/p/what-if-we-took-message-passing-seriously) -- the origin story and motivation behind Prompt Objects
192
+ - [As complexity grows, architecture](https://worksonmymachine.ai/p/as-complexity-grows-architecture) -- on why the hard problems are structural, not generative
193
+
194
+ ### Links
195
+
73
196
  - **Repository**: https://github.com/works-on-your-machine/prompt_objects
197
+ - **Changelog**: https://github.com/works-on-your-machine/prompt_objects/blob/main/CHANGELOG.md
198
+ - **License**: MIT
199
+ - **Ruby**: >= 3.2.0 (tested through Ruby 4)
data/frontend/index.html CHANGED
@@ -4,9 +4,13 @@
4
4
  <meta charset="UTF-8" />
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
8
+ <link href="https://cdn.jsdelivr.net/fontsource/fonts/geist@latest/latin-400-normal.woff2" as="font" type="font/woff2" crossorigin />
9
+ <link href="https://cdn.jsdelivr.net/npm/geist@1/dist/fonts/geist-sans/style.css" rel="stylesheet" />
10
+ <link href="https://cdn.jsdelivr.net/npm/geist@1/dist/fonts/geist-mono/style.css" rel="stylesheet" />
7
11
  <title>PromptObjects</title>
8
12
  </head>
9
- <body class="bg-po-bg text-gray-100">
13
+ <body class="bg-po-bg text-po-text-primary font-ui">
10
14
  <div id="root"></div>
11
15
  <script type="module" src="/src/main.tsx"></script>
12
16
  </body>
data/frontend/src/App.tsx CHANGED
@@ -1,103 +1,96 @@
1
- import { useState } from 'react'
2
1
  import { useWebSocket } from './hooks/useWebSocket'
3
2
  import { useStore, useSelectedPO } from './store'
4
- import { Header } from './components/Header'
5
- import { Dashboard } from './components/Dashboard'
6
- import { PODetail } from './components/PODetail'
7
- import { MessageBus } from './components/MessageBus'
3
+ import { useResize } from './hooks/useResize'
4
+ import { SystemBar } from './components/SystemBar'
5
+ import { ObjectList } from './components/ObjectList'
6
+ import { Inspector } from './components/Inspector'
7
+ import { Transcript } from './components/Transcript'
8
8
  import { NotificationPanel } from './components/NotificationPanel'
9
- import { ThreadsSidebar } from './components/ThreadsSidebar'
10
9
  import { UsagePanel } from './components/UsagePanel'
11
10
  import { CanvasView } from './canvas/CanvasView'
12
11
 
13
12
  export default function App() {
14
- const { sendMessage, respondToNotification, createSession, switchSession, switchLLM, createThread, updatePrompt, requestUsage, exportThread } =
13
+ const { sendMessage, respondToNotification, createSession, switchSession, switchLLM, createThread, updatePrompt, requestUsage, exportThread, requestEnvData } =
15
14
  useWebSocket()
16
15
  const { selectedPO, busOpen, notifications, usageData, clearUsageData, currentView } = useStore()
17
16
  const selectedPOData = useSelectedPO()
18
- const [splitView, setSplitView] = useState(true) // Default to split view
17
+
18
+ const objectListResize = useResize({
19
+ direction: 'horizontal',
20
+ initialSize: 192,
21
+ minSize: 120,
22
+ maxSize: 320,
23
+ })
24
+
25
+ const transcriptResize = useResize({
26
+ direction: 'vertical',
27
+ initialSize: 180,
28
+ minSize: 80,
29
+ maxSize: 400,
30
+ inverted: true,
31
+ })
19
32
 
20
33
  return (
21
34
  <div className="h-screen flex flex-col bg-po-bg">
22
- <Header switchLLM={switchLLM} />
35
+ <SystemBar switchLLM={switchLLM} />
23
36
 
24
- <div className="flex-1 flex overflow-hidden">
25
- {currentView === 'canvas' ? (
26
- <CanvasView />
27
- ) : (
28
- <>
29
- {/* Split view: Dashboard sidebar on left when PO selected */}
30
- {splitView && selectedPO && (
31
- <>
32
- {/* PO List */}
33
- <aside className="w-56 border-r border-po-border bg-po-surface overflow-hidden flex flex-col">
34
- <div className="p-3 border-b border-po-border flex items-center justify-between">
35
- <h2 className="text-sm font-medium text-gray-400">Prompt Objects</h2>
36
- <button
37
- onClick={() => setSplitView(false)}
38
- className="text-xs text-gray-500 hover:text-white"
39
- title="Hide sidebar"
40
- >
41
-
42
- </button>
43
- </div>
44
- <div className="flex-1 overflow-auto">
45
- <Dashboard compact />
46
- </div>
47
- </aside>
48
-
49
- {/* Threads List for selected PO */}
50
- {selectedPOData && (
51
- <aside className="w-56 border-r border-po-border bg-po-bg overflow-hidden">
52
- <ThreadsSidebar
53
- po={selectedPOData}
54
- switchSession={switchSession}
55
- createThread={createThread}
56
- requestUsage={requestUsage}
57
- exportThread={exportThread}
58
- />
59
- </aside>
60
- )}
61
- </>
62
- )}
37
+ <div className="flex-1 flex flex-col overflow-hidden">
38
+ {/* Main view area */}
39
+ <div className="flex-1 flex overflow-hidden">
40
+ {currentView === 'canvas' ? (
41
+ <CanvasView />
42
+ ) : (
43
+ <>
44
+ {/* Object List - resizable */}
45
+ <div style={{ width: objectListResize.size }} className="flex-shrink-0">
46
+ <ObjectList />
47
+ </div>
63
48
 
64
- {/* Main content */}
65
- <main className="flex-1 overflow-hidden flex flex-col">
66
- {/* Show expand button when sidebar is hidden */}
67
- {!splitView && selectedPO && (
68
- <button
69
- onClick={() => setSplitView(true)}
70
- className="absolute left-2 top-16 z-10 bg-po-surface border border-po-border rounded px-2 py-1 text-xs text-gray-400 hover:text-white hover:border-po-accent transition-colors"
71
- title="Show dashboard sidebar"
72
- >
73
- ☰ POs
74
- </button>
75
- )}
49
+ {/* Resize handle */}
50
+ <div
51
+ className="resize-handle"
52
+ onMouseDown={objectListResize.onMouseDown}
53
+ />
76
54
 
77
- {selectedPO ? (
78
- <PODetail
79
- sendMessage={sendMessage}
80
- createSession={createSession}
81
- switchSession={switchSession}
82
- createThread={createThread}
83
- updatePrompt={updatePrompt}
84
- />
85
- ) : (
86
- <Dashboard />
87
- )}
88
- </main>
89
- </>
90
- )}
55
+ {/* Main content */}
56
+ <main className="flex-1 overflow-hidden flex flex-col">
57
+ {selectedPO && selectedPOData ? (
58
+ <Inspector
59
+ po={selectedPOData}
60
+ sendMessage={sendMessage}
61
+ createSession={createSession}
62
+ switchSession={switchSession}
63
+ createThread={createThread}
64
+ updatePrompt={updatePrompt}
65
+ requestUsage={requestUsage}
66
+ exportThread={exportThread}
67
+ requestEnvData={requestEnvData}
68
+ />
69
+ ) : (
70
+ <div className="h-full flex items-center justify-center text-po-text-ghost">
71
+ <span className="font-mono text-xs">Select an object</span>
72
+ </div>
73
+ )}
74
+ </main>
75
+ </>
76
+ )}
77
+ </div>
91
78
 
92
- {/* Message Bus sidebar */}
79
+ {/* Transcript - resizable bottom pane, visible in both views */}
93
80
  {busOpen && (
94
- <aside className="w-80 flex-shrink-0 border-l border-po-border bg-po-surface overflow-hidden">
95
- <MessageBus />
96
- </aside>
81
+ <>
82
+ <div
83
+ className="resize-handle-h"
84
+ onMouseDown={transcriptResize.onMouseDown}
85
+ />
86
+ <div style={{ height: transcriptResize.size }} className="flex-shrink-0">
87
+ <Transcript />
88
+ </div>
89
+ </>
97
90
  )}
98
91
  </div>
99
92
 
100
- {/* Notification panel */}
93
+ {/* Notification panel - floating */}
101
94
  {notifications.length > 0 && (
102
95
  <NotificationPanel respondToNotification={respondToNotification} />
103
96
  )}
@@ -83,17 +83,17 @@ export function CanvasView() {
83
83
  <div className="absolute top-3 left-3 flex gap-2 z-10">
84
84
  <button
85
85
  onClick={() => sceneRef.current?.fitAll()}
86
- className="px-3 py-1.5 text-sm bg-po-surface/80 backdrop-blur border border-po-border rounded hover:border-po-accent transition-colors text-gray-300 hover:text-white"
86
+ className="px-2.5 py-1 text-xs bg-po-surface-2/80 backdrop-blur border border-po-border rounded hover:border-po-accent transition-colors duration-150 text-po-text-secondary hover:text-po-text-primary"
87
87
  title="Fit all nodes (F)"
88
88
  >
89
89
  Fit All
90
90
  </button>
91
91
  <button
92
92
  onClick={toggleLabels}
93
- className={`px-3 py-1.5 text-sm backdrop-blur border rounded transition-colors ${
93
+ className={`px-2.5 py-1 text-xs backdrop-blur border rounded transition-colors duration-150 ${
94
94
  showLabels
95
- ? 'bg-po-accent/20 border-po-accent text-white'
96
- : 'bg-po-surface/80 border-po-border text-gray-300 hover:text-white'
95
+ ? 'bg-po-accent-wash border-po-accent text-po-accent'
96
+ : 'bg-po-surface-2/80 border-po-border text-po-text-secondary hover:text-po-text-primary'
97
97
  }`}
98
98
  title="Toggle labels"
99
99
  >
@@ -102,7 +102,7 @@ export function CanvasView() {
102
102
  </div>
103
103
 
104
104
  {/* Help hint */}
105
- <div className="absolute bottom-3 left-3 text-xs text-gray-500 z-10">
105
+ <div className="absolute bottom-3 left-3 text-2xs text-po-text-ghost z-10 font-mono">
106
106
  Scroll to zoom · Shift+drag to pan · F to fit · Click node to inspect
107
107
  </div>
108
108