@octavus/docs 2.14.0 → 2.16.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.
@@ -141,6 +141,7 @@ export async function POST(request: Request) {
141
141
  'Content-Type': 'text/event-stream',
142
142
  'Cache-Control': 'no-cache',
143
143
  Connection: 'keep-alive',
144
+ 'X-Accel-Buffering': 'no',
144
145
  },
145
146
  });
146
147
  }
@@ -27,6 +27,7 @@ return new Response(toSSEStream(events), {
27
27
  'Content-Type': 'text/event-stream',
28
28
  'Cache-Control': 'no-cache',
29
29
  Connection: 'keep-alive',
30
+ 'X-Accel-Buffering': 'no',
30
31
  },
31
32
  });
32
33
 
@@ -36,6 +37,14 @@ for await (const event of events) {
36
37
  }
37
38
  ```
38
39
 
40
+ The `X-Accel-Buffering: no` header disables proxy buffering on Nginx-based infrastructure (including Vercel), ensuring SSE events are forwarded immediately instead of being batched.
41
+
42
+ ### Heartbeat
43
+
44
+ `toSSEStream` automatically sends SSE comment lines (`: heartbeat`) every 15 seconds during idle periods. This prevents proxies and load balancers from closing the connection due to inactivity — particularly important during multi-step executions where the stream may be silent while waiting for tool processing or LLM responses.
45
+
46
+ Heartbeat comments are ignored by all SSE parsers per the spec. No client-side handling is needed.
47
+
39
48
  ## Event Types
40
49
 
41
50
  The stream emits various event types for lifecycle, text, reasoning, and tool interactions.
@@ -80,6 +80,7 @@ export async function POST(request: Request) {
80
80
  'Content-Type': 'text/event-stream',
81
81
  'Cache-Control': 'no-cache',
82
82
  Connection: 'keep-alive',
83
+ 'X-Accel-Buffering': 'no',
83
84
  },
84
85
  });
85
86
  }
@@ -234,6 +235,7 @@ app.post('/api/trigger', async (req, res) => {
234
235
  res.setHeader('Content-Type', 'text/event-stream');
235
236
  res.setHeader('Cache-Control', 'no-cache');
236
237
  res.setHeader('Connection', 'keep-alive');
238
+ res.setHeader('X-Accel-Buffering', 'no');
237
239
 
238
240
  // Pipe the stream to the response
239
241
  const reader = stream.getReader();
@@ -107,17 +107,19 @@ This also works for named threads in interactive agents, allowing different thre
107
107
 
108
108
  When skills are enabled, the LLM has access to these tools:
109
109
 
110
- | Tool | Purpose |
111
- | -------------------- | --------------------------------------- |
112
- | `octavus_skill_read` | Read skill documentation (SKILL.md) |
113
- | `octavus_skill_list` | List available scripts in a skill |
114
- | `octavus_skill_run` | Execute a pre-built script from a skill |
115
- | `octavus_code_run` | Execute arbitrary Python/Bash code |
116
- | `octavus_file_write` | Create files in the sandbox |
117
- | `octavus_file_read` | Read files from the sandbox |
110
+ | Tool | Purpose | Availability |
111
+ | -------------------- | --------------------------------------- | -------------------- |
112
+ | `octavus_skill_read` | Read skill documentation (SKILL.md) | All skills |
113
+ | `octavus_skill_list` | List available scripts in a skill | All skills |
114
+ | `octavus_skill_run` | Execute a pre-built script from a skill | All skills |
115
+ | `octavus_code_run` | Execute arbitrary Python/Bash code | Standard skills only |
116
+ | `octavus_file_write` | Create files in the sandbox | Standard skills only |
117
+ | `octavus_file_read` | Read files from the sandbox | Standard skills only |
118
118
 
119
119
  The LLM learns about available skills through system prompt injection and can use these tools to interact with skills.
120
120
 
121
+ Skills that have [secrets](#skill-secrets) configured run in **secure mode**, where only `octavus_skill_read`, `octavus_skill_list`, and `octavus_skill_run` are available. See [Skill Secrets](#skill-secrets) below.
122
+
121
123
  ## Example: QR Code Generation
122
124
 
123
125
  ```yaml
@@ -212,6 +214,17 @@ Main script for generating QR codes...
212
214
 
213
215
  ````
214
216
 
217
+ ### Frontmatter Fields
218
+
219
+ | Field | Required | Description |
220
+ | ------------- | -------- | ------------------------------------------------------ |
221
+ | `name` | Yes | Skill slug (lowercase, hyphens) |
222
+ | `description` | Yes | What the skill does (shown to the LLM) |
223
+ | `version` | No | Semantic version string |
224
+ | `license` | No | License identifier |
225
+ | `author` | No | Skill author |
226
+ | `secrets` | No | Array of secret declarations (enables secure mode) |
227
+
215
228
  ## Best Practices
216
229
 
217
230
  ### 1. Clear Descriptions
@@ -337,6 +350,72 @@ steps:
337
350
 
338
351
  Thread-level `sandboxTimeout` takes priority over agent-level. Maximum: 1 hour (3,600,000 ms).
339
352
 
353
+ ## Skill Secrets
354
+
355
+ Skills can declare secrets they need to function. When an organization configures those secrets, the skill runs in **secure mode** with additional isolation.
356
+
357
+ ### Declaring Secrets
358
+
359
+ Add a `secrets` array to your SKILL.md frontmatter:
360
+
361
+ ```yaml
362
+ ---
363
+ name: github
364
+ description: >
365
+ Run GitHub CLI (gh) commands to manage repos, issues, PRs, and more.
366
+ secrets:
367
+ - name: GITHUB_TOKEN
368
+ description: GitHub personal access token with repo access
369
+ required: true
370
+ - name: GITHUB_ORG
371
+ description: Default GitHub organization
372
+ required: false
373
+ ---
374
+ ```
375
+
376
+ Each secret declaration has:
377
+
378
+ | Field | Required | Description |
379
+ | ------------- | -------- | ----------------------------------------------------------- |
380
+ | `name` | Yes | Environment variable name (uppercase, e.g., `GITHUB_TOKEN`) |
381
+ | `description` | No | Explains what this secret is for (shown in the UI) |
382
+ | `required` | No | Whether the secret is required (defaults to `true`) |
383
+
384
+ Secret names must match the pattern `^[A-Z_][A-Z0-9_]*$` (uppercase letters, digits, and underscores).
385
+
386
+ ### Configuring Secrets
387
+
388
+ Organization admins configure secret values through the skill editor in the platform UI. Each organization maintains its own independent set of secrets for each skill.
389
+
390
+ Secrets are encrypted at rest and only decrypted at execution time.
391
+
392
+ ### Secure Mode
393
+
394
+ When a skill has secrets configured for the organization, it automatically runs in **secure mode**:
395
+
396
+ - The skill gets its own **isolated sandbox** (separate from other skills)
397
+ - Secrets are injected as **environment variables** available to all scripts
398
+ - Only `octavus_skill_read`, `octavus_skill_list`, and `octavus_skill_run` are available — `octavus_code_run`, `octavus_file_write`, and `octavus_file_read` are blocked
399
+ - Scripts receive input as **JSON via stdin** (using the `input` parameter on `octavus_skill_run`) instead of CLI args
400
+ - All output (stdout/stderr) is **automatically redacted** for secret values before being returned to the LLM
401
+
402
+ ### Writing Scripts for Secure Skills
403
+
404
+ Scripts in secure skills read input from stdin as JSON and access secrets from environment variables:
405
+
406
+ ```python
407
+ import json
408
+ import os
409
+ import sys
410
+
411
+ input_data = json.load(sys.stdin)
412
+ token = os.environ.get('GITHUB_TOKEN')
413
+
414
+ # Use the token and input_data to perform the task
415
+ ```
416
+
417
+ For standard skills (without secrets), scripts receive input as CLI arguments. For secure skills, always use stdin JSON.
418
+
340
419
  ## Security
341
420
 
342
421
  Skills run in isolated sandbox environments:
@@ -345,6 +424,7 @@ Skills run in isolated sandbox environments:
345
424
  - **No persistent storage** (sandbox destroyed after each `next-message` execution)
346
425
  - **File output only** via `/output/` directory
347
426
  - **Time limits** enforced (5-minute default, configurable via `sandboxTimeout`)
427
+ - **Secret redaction** — output from secure skills is automatically scanned for secret values
348
428
 
349
429
  ## Next Steps
350
430
 
@@ -307,6 +307,76 @@ Pattern:
307
307
  2. LLM uses skill to analyze/process the data
308
308
  3. Generate outputs (files, reports)
309
309
 
310
+ ## Secure Skills
311
+
312
+ When a skill declares secrets and an organization configures them, the skill runs in secure mode with its own isolated sandbox.
313
+
314
+ ### Standard vs Secure Skills
315
+
316
+ | Aspect | Standard Skills | Secure Skills |
317
+ | ------------------- | --------------------------------- | --------------------------------------------------- |
318
+ | **Sandbox** | Shared with other standard skills | Isolated (one per skill) |
319
+ | **Available tools** | All 6 skill tools | `skill_read`, `skill_list`, `skill_run` only |
320
+ | **Script input** | CLI arguments via `args` | JSON via stdin (use `input` parameter) |
321
+ | **Environment** | No secrets | Secrets as env vars |
322
+ | **Output** | Raw stdout/stderr | Redacted (secret values replaced with `[REDACTED]`) |
323
+
324
+ ### Writing Scripts for Secure Skills
325
+
326
+ Secure skill scripts receive structured input via stdin (JSON) and access secrets from environment variables:
327
+
328
+ ```python
329
+ #!/usr/bin/env python3
330
+ import json
331
+ import os
332
+ import sys
333
+ import subprocess
334
+
335
+ input_data = json.load(sys.stdin)
336
+ token = os.environ["GITHUB_TOKEN"]
337
+
338
+ repo = input_data.get("repo", "")
339
+ result = subprocess.run(
340
+ ["gh", "repo", "view", repo, "--json", "name,description"],
341
+ capture_output=True, text=True,
342
+ env={**os.environ, "GH_TOKEN": token}
343
+ )
344
+
345
+ print(result.stdout)
346
+ ```
347
+
348
+ Key patterns:
349
+
350
+ - **Read stdin**: `json.load(sys.stdin)` to get the `input` object from the `octavus_skill_run` call
351
+ - **Access secrets**: `os.environ["SECRET_NAME"]` — secrets are injected as env vars
352
+ - **Print output**: Write results to stdout — the LLM sees the (redacted) stdout
353
+ - **Error handling**: Write errors to stderr and exit with non-zero code
354
+
355
+ ### Declaring Secrets in SKILL.md
356
+
357
+ ```yaml
358
+ ---
359
+ name: github
360
+ description: >
361
+ Run GitHub CLI (gh) commands to manage repos, issues, PRs, and more.
362
+ secrets:
363
+ - name: GITHUB_TOKEN
364
+ description: GitHub personal access token with repo access
365
+ required: true
366
+ - name: GITHUB_ORG
367
+ description: Default GitHub organization
368
+ required: false
369
+ ---
370
+ ```
371
+
372
+ ### Testing Secure Skills Locally
373
+
374
+ You can test scripts locally by piping JSON to stdin:
375
+
376
+ ```bash
377
+ echo '{"repo": "octavus-ai/agent-sdk"}' | GITHUB_TOKEN=ghp_xxx python scripts/list-issues.py
378
+ ```
379
+
310
380
  ## Skill Development Tips
311
381
 
312
382
  ### Writing SKILL.md
@@ -373,6 +443,15 @@ The LLM sees these errors and can retry or explain to users.
373
443
  - **File output only** via `/output/` directory
374
444
  - **Time limits** enforced (5-minute default, configurable via `sandboxTimeout`)
375
445
 
446
+ ### Secret Protection
447
+
448
+ For skills with configured secrets:
449
+
450
+ - **Isolated sandbox** — each secure skill gets its own sandbox, preventing cross-skill secret leakage
451
+ - **No arbitrary code** — `octavus_code_run`, `octavus_file_write`, and `octavus_file_read` are blocked for secure skills, so only pre-built scripts can execute
452
+ - **Output redaction** — all stdout and stderr are scanned for secret values before being returned to the LLM
453
+ - **Encrypted at rest** — secrets are encrypted using AES-256-GCM and only decrypted at execution time
454
+
376
455
  ### Input Validation
377
456
 
378
457
  Skills should validate inputs:
@@ -455,14 +534,16 @@ Check execution logs in the platform debug view:
455
534
 
456
535
  ## Best Practices Summary
457
536
 
458
- 1. **Enable only needed skills** - Don't overwhelm the LLM
459
- 2. **Choose appropriate display modes** - Match user experience needs
460
- 3. **Write clear skill descriptions** - Help LLM understand when to use
461
- 4. **Handle errors gracefully** - Provide helpful error messages
462
- 5. **Test skills locally** - Verify before uploading
463
- 6. **Monitor execution** - Check logs for issues
464
- 7. **Combine with tools** - Use tools for data, skills for processing
465
- 8. **Consider performance** - Be aware of timeouts and limits
537
+ 1. **Enable only needed skills** Don't overwhelm the LLM
538
+ 2. **Choose appropriate display modes** Match user experience needs
539
+ 3. **Write clear skill descriptions** Help LLM understand when to use
540
+ 4. **Handle errors gracefully** Provide helpful error messages
541
+ 5. **Test skills locally** Verify before uploading
542
+ 6. **Monitor execution** Check logs for issues
543
+ 7. **Combine with tools** Use tools for data, skills for processing
544
+ 8. **Consider performance** Be aware of timeouts and limits
545
+ 9. **Use secrets for credentials** — Declare secrets in frontmatter instead of hardcoding tokens
546
+ 10. **Design scripts for stdin input** — Secure skills receive JSON via stdin, so plan for both input methods if the skill might be used in either mode
466
547
 
467
548
  ## Next Steps
468
549
 
@@ -158,6 +158,7 @@ export async function POST(request: Request) {
158
158
  'Content-Type': 'text/event-stream',
159
159
  'Cache-Control': 'no-cache',
160
160
  Connection: 'keep-alive',
161
+ 'X-Accel-Buffering': 'no',
161
162
  },
162
163
  });
163
164
  }