Stateless agent loop for Go. LLMs think in plain text and act via $ prefixed shell commands — no tool schemas, no JSON.
prompt → LLM → scan for "$ command" → execute in sandbox → feed output back → repeat
go get github.com/tta-lab/logosresult, err := logos.Run(ctx, logos.Config{
Provider: provider, // fantasy.Provider (LLM abstraction)
Model: "claude-sonnet-4-6",
SystemPrompt: systemPrompt,
Temenos: temenosClient, // sandboxed command runner
SandboxEnv: map[string]string{"HOME": "/app"},
AllowedPaths: []client.AllowedPath{
{Path: "/app", Permission: "rw"},
},
}, history, "read main.go and explain what it does", logos.Callbacks{
OnDelta: func(text string) {
fmt.Print(text) // stream to terminal
},
OnCommandStart: func(cmd string) {
fmt.Printf("\n> %s\n", cmd)
},
})The LLM responds in plain text. When it wants to act, it writes a $ line:
Let me check the file structure first.
$ ls -la /app
logos detects the command, executes it in a temenos sandbox, and feeds the output back as the next user message. The loop continues until the LLM responds without a command.
Run()takes config, conversation history, a prompt, and streaming callbacks- Each turn, the LLM streams a response
scanForCommand()finds the first$line — one command per turn- The command runs via the
CommandRunnerinterface (temenos sandbox) - Output becomes the next user message; loop repeats
- When the LLM responds with no command, the loop ends and returns
RunResult
| Type | Purpose |
|---|---|
Config |
Provider, model, temenos client, sandbox env, allowed paths |
RunResult |
Final response text + all step messages |
StepMessage |
One message in the loop (assistant text or command output) |
Callbacks |
Optional OnDelta and OnCommandStart streaming hooks |
CommandRunner |
Interface for command execution — temenos satisfies it |
BuildSystemPrompt() renders an embedded template with runtime context (working dir, platform, date, available commands). Consumers typically append their own instructions after the base prompt:
base, _ := logos.BuildSystemPrompt(logos.PromptData{
WorkingDir: "/app",
Platform: "linux",
Date: "2026-03-16",
Commands: availableCommands,
})
systemPrompt := base + "\n\n" + customInstructions- Stateless —
Run()takes history in, returns steps out. The caller owns persistence. - One command per turn — finds the first
$line and stops; text after is ignored. - Sandboxed — commands execute in temenos, not on the host.
- Provider-agnostic — uses fantasy for LLM abstraction.
- fantasy — LLM provider abstraction (streaming, messages)
- temenos — sandboxed command execution daemon
MIT