11 KiB
id, title, status, assignee, created_date, updated_date, labels, dependencies, references, priority
| id | title | status | assignee | created_date | updated_date | labels | dependencies | references | priority | |
|---|---|---|---|---|---|---|---|---|---|---|
| ML-160 | Programmatic access to production logs | Done | 2026-05-04 06:42 | 2026-05-04 07:33 |
|
medium |
Description
Evaluate and implement the best approach for the LLM to access production logs. The /prod-logs pi extension lets the user see production logs via an interactive TUI, but the LLM has no access beyond the user selecting lines and pasting. The goal is to produce an extension/skill/tool that the LLM can use automatically when it needs to pull production logs. Reading logs from production is already implemented in /prod-logs as a fetchLogs function that hits the Coolify API — that code should be reused/shared where possible.
Acceptance Criteria
- #1 The LLM can fetch production logs without user intervention by calling the fetch_production_logs tool
- #2 The tool supports a
tailparameter to limit the number of log lines returned (default: 200) - #3 The tool supports a
grepparameter for case-insensitive filtering of log lines - #4 The tool returns log lines as text the LLM can read and analyze directly in context
- #5 When Coolify credentials are missing, the tool returns a clear error message listing which environment variables are not set
- #6 The existing /prod-logs interactive command continues to work unchanged
- #7 The tool description and guidelines teach the LLM when and how to use it effectively
Implementation Plan
Implementation Plan
Route: Pi Tool via pi.registerTool() (Route B)
Add a fetch_production_logs tool to the existing prod-logs pi extension using pi.registerTool(). The tool reuses the existing fetchLogs() and resolveVar() functions at module scope.
Step 1: Add Type import and fetch_production_logs tool registration
File: .pi/extensions/prod-logs/index.ts
Changes:
- Add
import { Type } from "typebox";to the existing imports block - Add
import { truncateTail, formatSize, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from "@mariozechner/pi-coding-agent";to the imports block - Inside the
prodLogsExtension()default export function, add api.registerTool()call (before or after the existingpi.registerCommand()call)
Tool specification:
name:"fetch_production_logs"description: Explains when the LLM should use this tool (investigating production errors, checking server behavior, debugging deployed issues). Mentions the 50KB/2000-line truncation limit.promptSnippet:"Fetch recent production logs from Coolify (param: tail, grep)"promptGuidelines: Three guidelines teaching the LLM when to use the tool, how to grep for relevant lines, and to start with small tail valuesparameters(TypeBox schema):tail—Type.Optional(Type.Number()), default 200, number of most recent log linesgrep—Type.Optional(Type.String()), case-insensitive filter pattern
Execute handler logic:
- Check
signal?.abortedearly — if aborted, return{ content: [{ type: "text", text: "Cancelled" }] } - Read Coolify credentials via
resolveVar("coolify_host"),resolveVar("coolify_app_uuid"),resolveVar("coolify_token") - If any credential is missing, return an error message listing which env vars are missing
- Call
fetchLogs(host, appUuid, token, signal)— reuses the existing function;signalis used for abort support - Handle fetch errors: return error text with the error message
- Handle empty logs: return "No log entries found"
- Apply grep filter if provided: case-insensitive
includesmatch on each line - Reverse lines (most recent first — consistent with the existing
/prod-logscommand behavior) - Apply tail:
lines.slice(0, tail)with default 200 - Join lines with
\ninto a single string - Apply output truncation via
truncateTailwithDEFAULT_MAX_BYTES(50KB) andDEFAULT_MAX_LINES(2000). If truncated, append a note:"\n\n[Output truncated: X of Y lines (A of B). Use a smaller 'tail' value or narrower 'grep' pattern to reduce output.]" - Return as text content, with
details: { lineCount }(the pre-truncation line count)
Verification
- Run
/reloadin pi to hot-reload the extension - Ask the LLM: "What tools are available for fetching production logs?" — it should describe
fetch_production_logs - Ask the LLM: "Fetch the last 50 lines of production logs" — verify it calls the tool and returns log text
- Ask the LLM: "Fetch production logs containing the word 'error'" — verify filtered output
- Temporarily unset one Coolify credential and ask the LLM to fetch logs — verify the tool returns a clear error listing which env var is missing
- Restore the credential, then ask the LLM to fetch logs with
tail: 5000from a busy period — verify truncation kicks in and the truncation note appears in the output - Run
/prod-logsmanually — verify the existing interactive command still works unchanged
Architecture Impact Analysis
| Touchpoint | Impact |
|---|---|
.pi/extensions/prod-logs/index.ts |
Modified — ~70 lines added (imports + tool registration + truncation) |
| Elixir modules | None — no changes |
| Schemas, PubSub, routes, UI | None — pi-only change |
| Config / env vars | None — same HURL_VARIABLE_coolify_* vars already in use |
Existing /prod-logs command |
Unchanged — tool registration is additive, independent of command registration |
Performance Profile
| Aspect | Characteristic |
|---|---|
| Runtime complexity | O(n) for grep filtering (single pass over log lines), O(1) for tail slice, O(n) for truncation byte counting |
| Network | Single HTTP GET to Coolify API; no retries in tool handler |
| Memory | Log response held in memory as string array; typically < 1MB for a few thousand lines; truncation caps return value at 50KB |
| Latency | Dominated by Coolify API response time (typically 1-5 seconds); local filtering negligible |
| Database | No database queries |
| State | Stateless — no caching, no persistence |
| N+1 risk | None — single API call |
Cost Profile
No paid resources consumed. The Coolify API is self-hosted as part of the deployment infrastructure. No third-party API calls, no additional compute or storage.
Production Infrastructure Steps
No production changes required:
- The
HURL_VARIABLE_coolify_*environment variables are already configured in the pi runtime environment (the existing/prod-logscommand already depends on them) - No new environment variables, service provisioning, DNS changes, or firewall rules
- No database migrations
- No rollout/rollback steps (the change is a single TypeScript file;
/reloadapplies it instantly)
Documentation Updates
No project documentation files need updating:
docs/architecture.md— already covers pi extensions generically; no new Elixir modules or architectural patterns introduceddocs/project-conventions.md— no new conventions introduceddocs/production-infrastructure.md— no infrastructure changesdocs/available-tasks.md— no new mise tasks
The implementation is self-documenting: the tool's description, promptSnippet, and promptGuidelines tell the LLM when and how to use it.
Dependencies
typebox— already available as a pi built-in import (listed in pi extension docs under "Available Imports")truncateTail,formatSize,DEFAULT_MAX_BYTES,DEFAULT_MAX_LINES— all from@mariozechner/pi-coding-agent, a pi built-in- No new npm dependencies needed
Implementation Notes
Added fetch_production_logs tool to the existing .pi/extensions/prod-logs/index.ts extension. The tool reuses the existing fetchLogs() and resolveVar() helper functions. Implementation follows the plan exactly:
- Added imports for
Type(typebox) andtruncateTail,formatSize,DEFAULT_MAX_BYTES,DEFAULT_MAX_LINES(@mariozechner/pi-coding-agent) - Registered tool before the existing
pi.registerCommand("prod-logs", ...)call - Tool supports
tail(default 200) andgrepparameters - Handler: credential check → fetch → error handling → empty check → reverse → grep → tail → join → truncate → return
- Truncation via
truncateTailwith 50KB/2000-line limit, with clear truncation note in output - Existing
/prod-logscommand code is completely untouched
Final Summary
Added a fetch_production_logs tool to .pi/extensions/prod-logs/index.ts using pi.registerTool(). The tool gives the LLM programmatic access to production logs without user intervention.
What changed:
- Added imports for
Type(typebox) andtruncateTail,formatSize,DEFAULT_MAX_BYTES,DEFAULT_MAX_LINESfrom@mariozechner/pi-coding-agent - Registered
fetch_production_logstool withtail(default 200) andgrepparameters - Tool reuses the existing
fetchLogs()andresolveVar()module-scope functions from the/prod-logsextension - Handler: credential validation → fetch → error handling → empty check → reverse (newest first) → grep filter → tail slice → join →
truncateTailtruncation with clear truncation note - On missing credentials, returns a clear error listing which env vars are not set
What didn't change:
- The existing
/prod-logsinteractive command code is completely untouched - No new dependencies, env vars, infrastructure changes, or Elixir module changes
Verification (requires /reload in pi):
- Ask the LLM about available tools for production logs — should describe
fetch_production_logs - Ask the LLM to fetch logs with
tail: 50orgrep: "error"— should work - Unset a credential and try — should get clear error message
- Run
/prod-logs— should still work unchanged