@soederpop/luca 0.0.32 → 0.0.34

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 (86) hide show
  1. package/README.md +241 -36
  2. package/bun.lock +24 -5
  3. package/commands/build-python-bridge.ts +43 -0
  4. package/docs/apis/clients/rest.md +7 -7
  5. package/docs/apis/clients/websocket.md +23 -10
  6. package/docs/apis/features/agi/assistant.md +155 -8
  7. package/docs/apis/features/agi/assistants-manager.md +90 -22
  8. package/docs/apis/features/agi/auto-assistant.md +377 -0
  9. package/docs/apis/features/agi/browser-use.md +802 -0
  10. package/docs/apis/features/agi/claude-code.md +6 -1
  11. package/docs/apis/features/agi/conversation-history.md +7 -6
  12. package/docs/apis/features/agi/conversation.md +111 -38
  13. package/docs/apis/features/agi/docs-reader.md +35 -57
  14. package/docs/apis/features/agi/file-tools.md +163 -0
  15. package/docs/apis/features/agi/openapi.md +2 -2
  16. package/docs/apis/features/agi/skills-library.md +227 -0
  17. package/docs/apis/features/node/content-db.md +125 -4
  18. package/docs/apis/features/node/disk-cache.md +11 -11
  19. package/docs/apis/features/node/downloader.md +1 -1
  20. package/docs/apis/features/node/file-manager.md +15 -15
  21. package/docs/apis/features/node/fs.md +78 -21
  22. package/docs/apis/features/node/git.md +50 -10
  23. package/docs/apis/features/node/google-calendar.md +3 -0
  24. package/docs/apis/features/node/google-docs.md +10 -1
  25. package/docs/apis/features/node/google-drive.md +3 -0
  26. package/docs/apis/features/node/google-mail.md +214 -0
  27. package/docs/apis/features/node/google-sheets.md +3 -0
  28. package/docs/apis/features/node/ink.md +10 -10
  29. package/docs/apis/features/node/ipc-socket.md +83 -93
  30. package/docs/apis/features/node/networking.md +5 -5
  31. package/docs/apis/features/node/os.md +7 -7
  32. package/docs/apis/features/node/package-finder.md +14 -14
  33. package/docs/apis/features/node/proc.md +2 -1
  34. package/docs/apis/features/node/process-manager.md +70 -3
  35. package/docs/apis/features/node/python.md +265 -9
  36. package/docs/apis/features/node/redis.md +380 -0
  37. package/docs/apis/features/node/ui.md +13 -13
  38. package/docs/apis/servers/express.md +35 -7
  39. package/docs/apis/servers/mcp.md +3 -3
  40. package/docs/apis/servers/websocket.md +51 -8
  41. package/docs/bootstrap/CLAUDE.md +1 -1
  42. package/docs/bootstrap/SKILL.md +93 -7
  43. package/docs/examples/feature-as-tool-provider.md +143 -0
  44. package/docs/examples/python.md +42 -1
  45. package/docs/introspection.md +15 -5
  46. package/docs/tutorials/00-bootstrap.md +3 -3
  47. package/docs/tutorials/02-container.md +2 -2
  48. package/docs/tutorials/10-creating-features.md +5 -0
  49. package/docs/tutorials/13-introspection.md +12 -2
  50. package/docs/tutorials/19-python-sessions.md +401 -0
  51. package/package.json +8 -4
  52. package/src/agi/container.server.ts +8 -0
  53. package/src/agi/features/assistant.ts +18 -0
  54. package/src/agi/features/autonomous-assistant.ts +435 -0
  55. package/src/agi/features/conversation.ts +58 -6
  56. package/src/agi/features/file-tools.ts +286 -0
  57. package/src/agi/features/luca-coder.ts +643 -0
  58. package/src/bootstrap/generated.ts +705 -17
  59. package/src/cli/build-info.ts +2 -2
  60. package/src/cli/cli.ts +22 -13
  61. package/src/commands/bootstrap.ts +49 -6
  62. package/src/commands/code.ts +369 -0
  63. package/src/commands/describe.ts +7 -2
  64. package/src/commands/index.ts +1 -0
  65. package/src/commands/sandbox-mcp.ts +7 -7
  66. package/src/commands/save-api-docs.ts +1 -1
  67. package/src/container-describer.ts +4 -4
  68. package/src/container.ts +10 -19
  69. package/src/helper.ts +24 -33
  70. package/src/introspection/generated.agi.ts +3026 -590
  71. package/src/introspection/generated.node.ts +1625 -688
  72. package/src/introspection/generated.web.ts +15 -57
  73. package/src/node/container.ts +5 -0
  74. package/src/node/features/figlet-fonts.ts +597 -0
  75. package/src/node/features/fs.ts +3 -9
  76. package/src/node/features/helpers.ts +20 -0
  77. package/src/node/features/python.ts +429 -16
  78. package/src/node/features/redis.ts +446 -0
  79. package/src/node/features/ui.ts +4 -11
  80. package/src/python/bridge.py +220 -0
  81. package/src/python/generated.ts +227 -0
  82. package/src/scaffolds/generated.ts +1 -1
  83. package/test/python-session.test.ts +105 -0
  84. package/assistants/lucaExpert/CORE.md +0 -37
  85. package/assistants/lucaExpert/hooks.ts +0 -9
  86. package/assistants/lucaExpert/tools.ts +0 -177
@@ -20,7 +20,7 @@ Parse markdown text and render it for terminal display using marked-terminal.
20
20
  |------|------|----------|-------------|
21
21
  | `text` | `string` | ✓ | The markdown string to parse and render |
22
22
 
23
- **Returns:** `void`
23
+ **Returns:** `string | Promise<string>`
24
24
 
25
25
 
26
26
 
@@ -64,7 +64,7 @@ Creates an interactive wizard using inquirer prompts. This method provides a con
64
64
  | `questions` | `any[]` | ✓ | Array of inquirer question objects |
65
65
  | `initialAnswers` | `any` | | Pre-populated answers to skip questions or provide defaults |
66
66
 
67
- **Returns:** `void`
67
+ **Returns:** `Promise<any>`
68
68
 
69
69
  ```ts
70
70
  // Basic wizard
@@ -109,7 +109,7 @@ Prompt the user with a single text input question.
109
109
  |------|------|----------|-------------|
110
110
  | `question` | `string` | ✓ | The question message to display |
111
111
 
112
- **Returns:** `void`
112
+ **Returns:** `Promise<any>`
113
113
 
114
114
 
115
115
 
@@ -124,7 +124,7 @@ Opens text in the user's external editor for editing. This method integrates wit
124
124
  | `text` | `string` | ✓ | The initial text content to edit |
125
125
  | `extension` | `any` | | File extension for syntax highlighting (default: ".ts") |
126
126
 
127
- **Returns:** `void`
127
+ **Returns:** `Promise<unknown>`
128
128
 
129
129
  ```ts
130
130
  // Edit code snippet
@@ -153,7 +153,7 @@ Generates ASCII art from text using the specified font. This method converts reg
153
153
  | `text` | `string` | ✓ | The text to convert to ASCII art |
154
154
  | `font` | `Fonts` | ✓ | The figlet font to use (see fonts property for available options) |
155
155
 
156
- **Returns:** `void`
156
+ **Returns:** `string`
157
157
 
158
158
  ```ts
159
159
  // Create a banner
@@ -191,7 +191,7 @@ Creates a styled banner with ASCII art and color gradients. This method combines
191
191
  | `font` | `any` | The figlet font to use for ASCII art generation |
192
192
  | `colors` | `any` | Array of colors for the gradient effect |
193
193
 
194
- **Returns:** `void`
194
+ **Returns:** `string`
195
195
 
196
196
  ```ts
197
197
  // Classic patriotic banner
@@ -229,7 +229,7 @@ Dedent and format a tagged template literal using endent. Strips leading indenta
229
229
  |------|------|----------|-------------|
230
230
  | `args` | `any[]` | ✓ | Tagged template literal arguments |
231
231
 
232
- **Returns:** `void`
232
+ **Returns:** `string`
233
233
 
234
234
 
235
235
 
@@ -245,7 +245,7 @@ Applies color gradients to text with configurable direction. This method creates
245
245
  | `lineColors` | `Color[]` | | Array of colors to cycle through in the gradient |
246
246
  | `direction` | `"horizontal" | "vertical"` | | Gradient direction: 'horizontal' or 'vertical' |
247
247
 
248
- **Returns:** `void`
248
+ **Returns:** `string`
249
249
 
250
250
  ```ts
251
251
  // Horizontal rainbow effect
@@ -281,7 +281,7 @@ Applies horizontal color gradients character by character. This method creates c
281
281
  | `text` | `string` | ✓ | The text to apply horizontal gradients to |
282
282
  | `lineColors` | `Color[]` | | Array of colors to cycle through |
283
283
 
284
- **Returns:** `void`
284
+ **Returns:** `string`
285
285
 
286
286
  ```ts
287
287
  // Rainbow effect across characters
@@ -310,7 +310,7 @@ Applies vertical color gradients line by line. This method creates color transit
310
310
  | `text` | `string` | ✓ | The text to apply vertical gradients to (supports newlines) |
311
311
  | `lineColors` | `Color[]` | | Array of colors to cycle through for each line |
312
312
 
313
- **Returns:** `void`
313
+ **Returns:** `string`
314
314
 
315
315
  ```ts
316
316
  // Patriotic vertical gradient
@@ -342,7 +342,7 @@ Pads text on the left to reach the specified length. This utility method adds pa
342
342
  | `length` | `number` | ✓ | The desired total length after padding |
343
343
  | `padChar` | `any` | | The character to use for padding (default: " ") |
344
344
 
345
- **Returns:** `void`
345
+ **Returns:** `string`
346
346
 
347
347
  ```ts
348
348
  // Number alignment
@@ -375,7 +375,7 @@ Pads text on the right to reach the specified length. This utility method adds p
375
375
  | `length` | `number` | ✓ | The desired total length after padding |
376
376
  | `padChar` | `any` | | The character to use for padding (default: " ") |
377
377
 
378
- **Returns:** `void`
378
+ **Returns:** `string`
379
379
 
380
380
  ```ts
381
381
  // Create aligned table columns
@@ -409,7 +409,7 @@ const menuItem = ui.padRight('Coffee', 20, '.') + '$3.50';
409
409
  |----------|------|-------------|
410
410
  | `colors` | `typeof colors` | Provides access to the full chalk colors API. Chalk provides extensive color and styling capabilities including: - Basic colors: red, green, blue, yellow, etc. - Background colors: bgRed, bgGreen, etc. - Styles: bold, italic, underline, strikethrough - Advanced: rgb, hex, hsl color support Colors and styles can be chained for complex formatting. |
411
411
  | `colorPalette` | `string[]` | Gets the current color palette used for automatic color assignment. The color palette is a predefined set of hex colors that are automatically assigned to named entities in a cycling fashion. This ensures consistent color assignment across the application. |
412
- | `randomColor` | `any` | Gets a random color name from the available chalk colors. This provides access to a randomly selected color from chalk's built-in color set. Useful for adding variety to terminal output or testing. |
412
+ | `randomColor` | `string | undefined` | Gets a random color name from the available chalk colors. This provides access to a randomly selected color from chalk's built-in color set. Useful for adding variety to terminal output or testing. |
413
413
  | `fonts` | `string[]` | Gets an array of available fonts for ASCII art generation. This method provides access to all fonts available through figlet for creating ASCII art. The fonts are automatically discovered and cached on first access for performance. **Font Discovery:** - Fonts are loaded from figlet's built-in font collection - Results are cached in state to avoid repeated file system access - Returns comprehensive list of available font names |
414
414
 
415
415
  ## State (Zod v4 schema)
@@ -39,25 +39,27 @@ container.server('express', {
39
39
 
40
40
  ### start
41
41
 
42
+ Start the Express HTTP server. A runtime `port` overrides the constructor option and is written to state so `server.port` always reflects reality.
43
+
42
44
  **Parameters:**
43
45
 
44
46
  | Name | Type | Required | Description |
45
47
  |------|------|----------|-------------|
46
- | `options` | `StartOptions` | | Parameter options |
48
+ | `options` | `StartOptions` | | Optional runtime overrides for port and host |
47
49
 
48
- **Returns:** `void`
50
+ **Returns:** `Promise<this>`
49
51
 
50
52
 
51
53
 
52
54
  ### stop
53
55
 
54
- **Returns:** `void`
56
+ **Returns:** `Promise<this>`
55
57
 
56
58
 
57
59
 
58
60
  ### configure
59
61
 
60
- **Returns:** `void`
62
+ **Returns:** `Promise<this>`
61
63
 
62
64
 
63
65
 
@@ -85,6 +87,32 @@ container.server('express', {
85
87
 
86
88
 
87
89
 
90
+ ### reloadEndpoint
91
+
92
+ Reload a mounted endpoint by its file path. Re-reads the module through the helpers VM loader so the next request picks up the new handlers.
93
+
94
+ **Parameters:**
95
+
96
+ | Name | Type | Required | Description |
97
+ |------|------|----------|-------------|
98
+ | `filePath` | `string` | ✓ | Absolute path to the endpoint file |
99
+
100
+ **Returns:** `Promise<Endpoint | null>`
101
+
102
+
103
+
104
+ ### useEndpointModules
105
+
106
+ **Parameters:**
107
+
108
+ | Name | Type | Required | Description |
109
+ |------|------|----------|-------------|
110
+ | `modules` | `EndpointModule[]` | ✓ | Parameter modules |
111
+
112
+ **Returns:** `Promise<this>`
113
+
114
+
115
+
88
116
  ### serveOpenAPISpec
89
117
 
90
118
  **Parameters:**
@@ -113,9 +141,9 @@ container.server('express', {
113
141
 
114
142
  | Property | Type | Description |
115
143
  |----------|------|-------------|
116
- | `express` | `any` | |
117
- | `hooks` | `any` | |
118
- | `app` | `any` | |
144
+ | `express` | `typeof express` | |
145
+ | `hooks` | `{ create: (app: Express, server: Server) => Express; beforeStart: (options: any, server: Server) => any }` | |
146
+ | `app` | `Express` | |
119
147
 
120
148
  ## State (Zod v4 schema)
121
149
 
@@ -102,7 +102,7 @@ Register an MCP prompt. Prompts are reusable message templates that AI clients c
102
102
 
103
103
  Configure the MCP protocol server and register all protocol handlers. Called automatically before start() if not already configured.
104
104
 
105
- **Returns:** `void`
105
+ **Returns:** `Promise<this>`
106
106
 
107
107
 
108
108
 
@@ -135,7 +135,7 @@ Start the MCP server with the specified transport.
135
135
  | `transport` | `any` | 'stdio' for CLI integration, 'http' for remote access |
136
136
  | `port` | `any` | Port for HTTP transport (default 3001) |
137
137
 
138
- **Returns:** `void`
138
+ **Returns:** `Promise<this>`
139
139
 
140
140
 
141
141
 
@@ -143,7 +143,7 @@ Start the MCP server with the specified transport.
143
143
 
144
144
  Stop the MCP server and close all connections.
145
145
 
146
- **Returns:** `void`
146
+ **Returns:** `Promise<this>`
147
147
 
148
148
 
149
149
 
@@ -1,6 +1,6 @@
1
1
  # WebsocketServer (servers.websocket)
2
2
 
3
- WebSocket server built on the `ws` library with optional JSON message framing. Manages WebSocket connections, tracks connected clients, and bridges messages to Luca's event bus. When `json` mode is enabled, incoming messages are automatically JSON-parsed (with `.toString()` for Buffer data) and outgoing messages via `send()` / `broadcast()` are JSON-stringified. When `json` mode is disabled, raw message data is emitted as-is and `send()` / `broadcast()` still JSON-stringify for safety.
3
+ WebSocket server built on the `ws` library with optional JSON message framing. Manages WebSocket connections, tracks connected clients, and bridges messages to Luca's event bus. When `json` mode is enabled, incoming messages are automatically JSON-parsed (with `.toString()` for Buffer data) and outgoing messages via `send()` / `broadcast()` are JSON-stringified. When `json` mode is disabled, raw message data is emitted as-is and `send()` / `broadcast()` still JSON-stringify for safety. Supports ask/reply semantics when paired with the Luca WebSocket client. The server can `ask(ws, type, data)` a connected client and await a typed response, or handle incoming asks from clients by listening for messages with a `requestId` and replying via `send(ws, { replyTo, data })`. Requests time out if no reply arrives within the configurable window.
4
4
 
5
5
  ## Usage
6
6
 
@@ -33,7 +33,7 @@ container.server('websocket', {
33
33
  |------|------|----------|-------------|
34
34
  | `message` | `any` | ✓ | Parameter message |
35
35
 
36
- **Returns:** `void`
36
+ **Returns:** `Promise<this>`
37
37
 
38
38
 
39
39
 
@@ -46,25 +46,51 @@ container.server('websocket', {
46
46
  | `ws` | `any` | ✓ | Parameter ws |
47
47
  | `message` | `any` | ✓ | Parameter message |
48
48
 
49
- **Returns:** `void`
49
+ **Returns:** `Promise<this>`
50
+
51
+
52
+
53
+ ### ask
54
+
55
+ Send a request to a specific client and wait for a correlated response. The client is expected to reply with a message whose `replyTo` matches the `requestId` of this message.
56
+
57
+ **Parameters:**
58
+
59
+ | Name | Type | Required | Description |
60
+ |------|------|----------|-------------|
61
+ | `ws` | `any` | ✓ | The WebSocket client to ask |
62
+ | `type` | `string` | ✓ | A string identifying the request type |
63
+ | `data` | `any` | | Optional payload |
64
+ | `timeout` | `any` | | How long to wait (default 10 000 ms) |
65
+
66
+ **Returns:** `Promise<R>`
67
+
68
+ ```ts
69
+ ws.on('connection', async (client) => {
70
+ const info = await ws.ask(client, 'identify')
71
+ console.log('Client says:', info)
72
+ })
73
+ ```
50
74
 
51
75
 
52
76
 
53
77
  ### start
54
78
 
79
+ Start the WebSocket server. A runtime `port` overrides the constructor option and is written to state before the underlying `ws.Server` is created, so the server binds to the correct port.
80
+
55
81
  **Parameters:**
56
82
 
57
83
  | Name | Type | Required | Description |
58
84
  |------|------|----------|-------------|
59
- | `options` | `StartOptions` | | Parameter options |
85
+ | `options` | `StartOptions` | | Optional runtime overrides for port and host |
60
86
 
61
- **Returns:** `void`
87
+ **Returns:** `Promise<this>`
62
88
 
63
89
 
64
90
 
65
91
  ### stop
66
92
 
67
- **Returns:** `void`
93
+ **Returns:** `Promise<this>`
68
94
 
69
95
 
70
96
 
@@ -72,8 +98,8 @@ container.server('websocket', {
72
98
 
73
99
  | Property | Type | Description |
74
100
  |----------|------|-------------|
75
- | `wss` | `any` | |
76
- | `port` | `any` | |
101
+ | `wss` | `BaseServer` | |
102
+ | `port` | `number` | The port this server will bind to. Defaults to 8081 if not set via constructor options or start(). |
77
103
 
78
104
  ## Events (Zod v4 schema)
79
105
 
@@ -123,5 +149,22 @@ ws.on('message', (data, client) => {
123
149
  console.log('Received:', data)
124
150
  ws.broadcast({ echo: data })
125
151
  })
152
+
153
+ // ask/reply: request info from a connected client
154
+ ws.on('connection', async (client) => {
155
+ const info = await ws.ask(client, 'identify')
156
+ console.log('Client says:', info)
157
+ })
158
+ ```
159
+
160
+
161
+
162
+ **ask**
163
+
164
+ ```ts
165
+ ws.on('connection', async (client) => {
166
+ const info = await ws.ask(client, 'identify')
167
+ console.log('Client says:', info)
168
+ })
126
169
  ```
127
170
 
@@ -32,7 +32,7 @@ The `luca` binary is available in the path. Key commands:
32
32
  1. **Discover** — Run `luca describe features`, `luca describe clients`, `luca describe servers` to see what's available. Then `luca describe <name>` for full docs on any helper, or `luca describe <name>.<member>` to drill into a specific method or getter. This is your first move, always. (See `.claude/skills/luca-framework/SKILL.md` for the full mental model.)
33
33
  2. **Build** — Run `luca scaffold <type> --tutorial` before creating a new helper. It covers the full guide for that type.
34
34
  3. **Prototype** — Use `luca eval "expression"` to test container code before wiring up full handlers. Reach for eval when you're stuck — it gives you full runtime access.
35
- 4. **Reference** — Browse `.claude/skills/luca-framework/references/` for pre-generated API docs, runnable examples, and tutorials
35
+ 4. **Reference** — The skill file (`.claude/skills/luca-framework/SKILL.md`) includes a full Framework Index with every feature, client, and server organized by category
36
36
 
37
37
  ## Project Structure
38
38
 
@@ -18,7 +18,7 @@ There are three things to learn, in this order:
18
18
 
19
19
  ## Phase 1: Discover with `luca describe`
20
20
 
21
- This is your primary tool. Before reading source files, searching for APIs, or writing any codeask describe. It outputs full documentation for any part of the container: methods, options, events, state, examples.
21
+ This is your primary tool. The `luca` binary is a compiled artifact that bundles all introspection data it is the authority on what the container provides. Run `luca describe` first — it outputs full documentation for any part of the container: methods, options, events, state, examples. Reading source can be helpful for additional context if it exists in the project, but the source for built-in helpers may not be present — the binary is always the ground truth.
22
22
 
23
23
  ### See what's available
24
24
 
@@ -70,6 +70,18 @@ luca describe fs git --examples # just examples for both
70
70
  luca describe fs --usage --methods # combine sections
71
71
  ```
72
72
 
73
+ ### Get approximate TypeScript types
74
+
75
+ Need to know the shape of a helper for type-safe code? Use `--ts`:
76
+
77
+ ```shell
78
+ luca describe fs --ts # approximate TS interface for fs
79
+ luca describe conversation --ts # see the conversation feature's type surface
80
+ luca describe rest --ts # client type shape
81
+ ```
82
+
83
+ This outputs a ~95% accurate TypeScript representation based on runtime introspection. If a type looks wrong or a method signature seems off, verify with `luca eval` against the live instance.
84
+
73
85
  ### Describe the container itself
74
86
 
75
87
  ```shell
@@ -85,7 +97,9 @@ luca describe --help # full flag reference for describe
85
97
  luca help scaffold # help for any command
86
98
  ```
87
99
 
88
- **Use `luca describe` liberally.** It is the fastest, safest way to understand what the container provides. Every feature, client, and server is self-describing — if you know a name, describe will tell you everything about it. Use dot notation (`ui.banner`, `fs.readFile`) when you need docs on just one method or getter.
100
+ **Use `luca describe` liberally.** It is the fastest, safest way to understand what the container provides. Every feature, client, and server is self-describing — if you know a name, describe will tell you everything about it. Use dot notation (`ui.banner`, `fs.readFile`) when you need docs on just one method or getter. Use `--ts` when you need type information for writing code.
101
+
102
+ > **NOTE:** The `luca` binary is compiled and bundles all introspection data. `luca describe` reflects what actually ships in the binary — source files for built-in helpers may not exist in your project. Reading source can add context when it's available, but `luca describe` and `luca eval` are always the authority.
89
103
 
90
104
  ---
91
105
 
@@ -232,7 +246,7 @@ Everything `luca describe` outputs is also available at runtime in code:
232
246
  ```js
233
247
  container.features.describe('fs') // markdown docs (same as the CLI)
234
248
  feature.introspect() // structured object: { methods, events, state, options }
235
- container.inspectAsText() // full container overview as markdown
249
+ container.introspectAsText() // full container overview as markdown
236
250
  ```
237
251
 
238
252
  This is useful inside commands and scripts where you need introspection data programmatically.
@@ -248,8 +262,80 @@ This is useful inside commands and scripts where you need introspection data pro
248
262
  - `luca serve --any-port` will open on any port
249
263
 
250
264
 
251
- ## Reference
265
+ ## Framework Index
266
+
267
+ A table of contents for the container. **Run `luca describe <name>` for full docs on any item.** Use `luca describe <name> --ts` when you need type information. Source may not exist locally for built-in helpers — the compiled binary is the authority.
268
+
269
+ ### Features by Category
270
+
271
+ | Category | Features | What they do |
272
+ |----------|----------|--------------|
273
+ | **File System & Code** | `fs`, `grep`, `fileManager` | Read/write files, search code, watch for changes |
274
+ | **Process & Shell** | `proc`, `processManager`, `secureShell` | Run commands, manage long-running processes, SSH |
275
+ | **AI Assistants** | `assistant`, `assistantsManager`, `conversation`, `conversationHistory`, `fileTools` | Build AI assistants, manage conversations, tool calling. `fileTools` composes lower-level features (`fs`, `grep`) into an assistant-ready tool surface — a good example of how features can define tools for assistants (see `references/examples/feature-as-tool-provider.md`). |
276
+ | **AI Agent Wrappers** | `claudeCode`, `openaiCodex`, `lucaCoder` | Spawn and manage external AI agent CLIs as subprocesses |
277
+ | **Data & Storage** | `sqlite`, `postgres`, `diskCache`, `contentDb`, `redis` | Databases, caching, document management |
278
+ | **Networking** | `networking`, `dns`, `portExposer` | Network utilities, DNS, tunneling |
279
+ | **Google Workspace** | `googleAuth`, `googleDrive`, `googleDocs`, `googleSheets`, `googleCalendar`, `googleMail` | OAuth and Google service wrappers |
280
+ | **Dev Tools** | `git`, `docker`, `esbuild`, `vm`, `python`, `packageFinder` | Version control, containers, bundling, sandboxed execution |
281
+ | **Content & NLP** | `docsReader`, `nlp`, `semanticSearch`, `skillsLibrary`, `jsonTree`, `yamlTree` | Document Q&A, text analysis, semantic search, skills, structured file ingestion |
282
+ | **UI & Output** | `ui`, `ink`, `yaml` | Terminal UI, colors, ascii art, structured data display |
283
+ | **Media & Browser** | `browserUse`, `tts`, `downloader`, `opener`, `telegram` | Browser automation, text-to-speech, downloads, messaging |
284
+ | **System** | `os`, `vault`, `helpers`, `introspectionScanner`, `containerLink`, `repl`, `runpod` | OS info, secrets, runtime introspection, remote container linking |
285
+
286
+ ### Clients
287
+
288
+ | Client | Purpose |
289
+ |--------|---------|
290
+ | `openai` | Chat completions, embeddings, image generation |
291
+ | `rest` | Generic HTTP client (GET/POST/PUT/PATCH/DELETE) |
292
+ | `websocket` | WebSocket connections |
293
+ | `elevenlabs` | Text-to-speech synthesis |
294
+ | `graph` | GraphQL queries and mutations |
295
+
296
+ ### Servers
297
+
298
+ | Server | Purpose |
299
+ |--------|---------|
300
+ | `express` | HTTP server with file-based endpoint routing |
301
+ | `mcp` | Model Context Protocol server for AI tool exposure |
302
+ | `websocket` | WebSocket server with JSON framing |
303
+ | `ipcSocket` | Local IPC socket server for inter-process communication |
304
+
305
+ ### Type Discovery
306
+
307
+ `luca describe <name> --ts` outputs an approximate TypeScript representation of any helper as it exists at runtime — ~95% accurate. This is your go-to for writing type-safe code against the container. The binary compiles in the introspection data, so `--ts` reflects what actually exists at runtime even when source isn't available. Reading source can provide additional context when it's there.
308
+
309
+ ```shell
310
+ luca describe fs --ts # approximate TS interface for the fs feature
311
+ luca describe conversation --ts # conversation feature type surface
312
+ luca describe express --ts # express server type shape
313
+ ```
314
+
315
+ If a method signature or return type looks wrong, verify with `luca eval`:
316
+
317
+ ```shell
318
+ luca eval "typeof container.feature('fs').readFile"
319
+ luca eval "container.feature('fs').readFile('package.json')"
320
+ ```
321
+
322
+ ### Bundled Examples and Tutorials
323
+
324
+ The skill directory includes reference material:
325
+
326
+ - **`references/examples/`** — short, focused example docs for individual features (e.g. `fs.md`, `git.md`, `proc.md`)
327
+ - **`references/tutorials/`** — longer-form guides covering the container, helpers, commands, endpoints, state/events, assistants, and more
328
+
329
+ These complement `luca describe` — describe gives you the API surface, examples show you patterns in action, and tutorials walk through building things end to end.
330
+
331
+ **Tip:** Runnable markdown is a great artifact to produce when building with luca. `luca run doc.md` executes code blocks inside the Luca VM — useful for both testing and documentation. When prototyping a feature or writing a how-to, consider writing it as a markdown file that can be run.
332
+
333
+ ### Container Primitives
252
334
 
253
- - `references/api-docs/` full pre-generated API reference for every built-in feature, client, and server
254
- - `references/examples/` — runnable example docs for each feature (e.g. `fs.md`, `git.md`, `proc.md`)
255
- - `references/tutorials/` step-by-step tutorials covering the container, helpers, commands, endpoints, and more
335
+ | Primitive | Access | Purpose |
336
+ |-----------|--------|---------|
337
+ | State | `container.state`, `helper.state` | Observable key-value state on every object |
338
+ | Events | `container.on()`, `helper.on()` | Event bus on every object |
339
+ | Paths | `container.paths` | `resolve()`, `join()`, `cwd` |
340
+ | Utils | `container.utils` | `uuid()`, `lodash`, `stringUtils`, `hashObject()` |
341
+ | Registries | `container.features`, `.clients`, `.servers` | Discovery and metadata for all helpers |
@@ -0,0 +1,143 @@
1
+ ---
2
+ title: "Features as Tool Providers for Assistants"
3
+ tags: [feature, tools, assistant, composition, use, setupToolsConsumer]
4
+ lastTested: null
5
+ lastTestPassed: null
6
+ ---
7
+
8
+ # Features as Tool Providers for Assistants
9
+
10
+ Any feature can expose tools that assistants pick up via `assistant.use(feature)`. This is how you compose lower-level container capabilities into an assistant-ready tool surface. The built-in `fileTools` feature is the canonical example — it wraps `fs` and `grep` into a focused set of tools modeled on what coding assistants need.
11
+
12
+ ## The Pattern
13
+
14
+ A feature becomes a tool provider by defining three things:
15
+
16
+ 1. **`static tools`** — a record mapping tool names to Zod schemas with descriptions
17
+ 2. **Matching methods** — instance methods whose names match the keys in `static tools`
18
+ 3. **`setupToolsConsumer()`** (optional) — a hook that runs when an assistant calls `use()`, perfect for injecting system prompt guidance
19
+
20
+ When an assistant calls `assistant.use(feature)`, the framework:
21
+ - Reads `static tools` to register each tool with its schema
22
+ - Routes tool calls to the matching instance methods
23
+ - Calls `setupToolsConsumer()` so the feature can configure the assistant (e.g. add system prompt extensions)
24
+
25
+ ## Anatomy of fileTools
26
+
27
+ Here's the structure of the built-in `fileTools` feature (simplified for clarity):
28
+
29
+ ```ts
30
+ import { z } from 'zod'
31
+ import { Feature } from '@soederpop/luca/feature'
32
+
33
+ export class FileTools extends Feature {
34
+ static { Feature.register(this, 'fileTools') }
35
+
36
+ // ── 1. Declare tools with Zod schemas ──────────────────────────
37
+ static tools = {
38
+ readFile: {
39
+ description: 'Read the contents of a file.',
40
+ schema: z.object({
41
+ path: z.string().describe('File path relative to the project root'),
42
+ offset: z.number().optional().describe('Line number to start reading from'),
43
+ limit: z.number().optional().describe('Maximum number of lines to read'),
44
+ }),
45
+ },
46
+ searchFiles: {
47
+ description: 'Search file contents for a pattern using ripgrep.',
48
+ schema: z.object({
49
+ pattern: z.string().describe('Search pattern (regex supported)'),
50
+ path: z.string().optional().describe('Directory to search in'),
51
+ include: z.string().optional().describe('Glob pattern to filter files'),
52
+ }),
53
+ },
54
+ editFile: {
55
+ description: 'Replace an exact string match in a file.',
56
+ schema: z.object({
57
+ path: z.string().describe('File path relative to the project root'),
58
+ oldString: z.string().describe('The exact text to find and replace'),
59
+ newString: z.string().describe('The replacement text'),
60
+ }),
61
+ },
62
+ // ... more tools
63
+ }
64
+
65
+ // ── 2. Implement each tool as an instance method ───────────────
66
+ // Method names must match the keys in static tools exactly.
67
+ // Each receives the parsed args object and returns a string.
68
+
69
+ async readFile(args: { path: string; offset?: number; limit?: number }) {
70
+ const fs = this.container.feature('fs')
71
+ const content = await fs.readFileAsync(args.path)
72
+ // ... handle offset/limit
73
+ return content
74
+ }
75
+
76
+ async searchFiles(args: { pattern: string; path?: string; include?: string }) {
77
+ const grep = this.container.feature('grep')
78
+ const results = await grep.search({ pattern: args.pattern, path: args.path, include: args.include })
79
+ return JSON.stringify(results.map(r => ({ file: r.file, line: r.line, content: r.content })))
80
+ }
81
+
82
+ async editFile(args: { path: string; oldString: string; newString: string }) {
83
+ const fs = this.container.feature('fs')
84
+ const content = await fs.readFileAsync(args.path)
85
+ const updated = content.replace(args.oldString, args.newString)
86
+ await fs.writeFileAsync(args.path, updated)
87
+ return `Edited ${args.path}`
88
+ }
89
+
90
+ // ── 3. Configure the assistant when it calls use() ─────────────
91
+ override setupToolsConsumer(consumer) {
92
+ // If the consumer is an assistant, inject guidance into its system prompt
93
+ if (typeof consumer.addSystemPromptExtension === 'function') {
94
+ consumer.addSystemPromptExtension('fileTools', [
95
+ '## File Tools',
96
+ '- All file paths are relative to the project root unless they start with /',
97
+ '- Use searchFiles to understand code before modifying it',
98
+ '- Use editFile for surgical changes — prefer it over writeFile',
99
+ ].join('\n'))
100
+ }
101
+ }
102
+ }
103
+ ```
104
+
105
+ ## Using It
106
+
107
+ ```ts
108
+ const assistant = container.feature('assistant', {
109
+ systemPrompt: 'You are a coding assistant.',
110
+ model: 'gpt-4.1-mini',
111
+ })
112
+
113
+ const fileTools = container.feature('fileTools')
114
+ assistant.use(fileTools)
115
+ await assistant.start()
116
+
117
+ // The assistant now has readFile, searchFiles, editFile, etc.
118
+ // and its system prompt includes the fileTools guidance.
119
+ console.log(Object.keys(assistant.tools))
120
+ ```
121
+
122
+ ### Selective tool registration
123
+
124
+ You can expose only a subset of tools:
125
+
126
+ ```ts
127
+ assistant.use(fileTools.toTools({ only: ['readFile', 'searchFiles', 'listDirectory'] }))
128
+ ```
129
+
130
+ ## Why This Pattern Matters
131
+
132
+ This is how features compose for AI. Instead of the assistant importing `fs` and `grep` directly:
133
+
134
+ - The **feature** owns the tool surface — schemas, descriptions, and implementations in one place
135
+ - The **assistant** gets a curated interface, not raw container access
136
+ - **`setupToolsConsumer()`** lets the feature teach the assistant how to use the tools well
137
+ - **`toTools({ only })`** lets you scope down what the assistant can do
138
+
139
+ Any feature you build can follow this same pattern. Define `static tools`, implement matching methods, optionally override `setupToolsConsumer()`, and assistants can `use()` it.
140
+
141
+ ## Summary
142
+
143
+ Features are the natural place to package tools for assistants. The `static tools` record declares the schema, instance methods implement the logic, and `setupToolsConsumer()` wires up assistant-specific configuration like system prompt extensions. This keeps tool definitions, implementations, and assistant guidance co-located in a single feature class.
@@ -86,6 +86,47 @@ console.log('Install exit code:', result.exitCode)
86
86
 
87
87
  When no `installCommand` is provided, the feature infers the correct command from the detected environment type (e.g., `uv sync` for uv, `pip install -e .` for venv).
88
88
 
89
+ ## Persistent Sessions
90
+
91
+ Start a long-lived Python process where state persists across calls. Ideal for working inside real Python codebases, data analysis, and anything with expensive setup.
92
+
93
+ ```ts skip
94
+ const python = container.feature('python', { dir: '/path/to/python-project' })
95
+ await python.enable()
96
+ await python.startSession()
97
+
98
+ // State persists across calls
99
+ await python.run('x = 42')
100
+ const result = await python.run('print(x * 2)')
101
+ console.log('stdout:', result.stdout) // '84\n'
102
+
103
+ // Evaluate expressions and get values back
104
+ const val = await python.eval('x + 1')
105
+ console.log('eval:', val) // 43
106
+
107
+ // Import project modules (sys.path is set up automatically)
108
+ await python.importModule('json')
109
+ const encoded = await python.call('json.dumps', [{ key: 'value' }], { indent: 2 })
110
+ console.log('call:', encoded)
111
+
112
+ // Inspect the namespace
113
+ const locals = await python.getLocals()
114
+ console.log('locals:', Object.keys(locals))
115
+
116
+ // Errors don't crash the session
117
+ const bad = await python.run('raise ValueError("oops")')
118
+ console.log('error:', bad.error) // 'oops'
119
+
120
+ // Still alive
121
+ const check = await python.run('print("still here")')
122
+ console.log(check.stdout) // 'still here\n'
123
+
124
+ // Clean up
125
+ await python.stopSession()
126
+ ```
127
+
128
+ See the [Python Sessions tutorial](../tutorials/19-python-sessions.md) for real-world patterns (data pipelines, Django, ML models).
129
+
89
130
  ## Summary
90
131
 
91
- The `python` feature bridges Luca and Python by auto-detecting environments, managing dependencies, and providing inline code execution with variable injection. It supports uv, conda, venv, and system Python installations.
132
+ The `python` feature bridges Luca and Python by auto-detecting environments, managing dependencies, and providing both stateless execution and persistent sessions. It supports uv, conda, venv, and system Python installations.