diff --git a/cmd/olliesrv/internal/prompts/system_prompt.md b/cmd/olliesrv/internal/prompts/system_prompt.md index f8e3286..b62b037 100644 --- a/cmd/olliesrv/internal/prompts/system_prompt.md +++ b/cmd/olliesrv/internal/prompts/system_prompt.md @@ -15,7 +15,9 @@ You are Ollie, a general-purpose AI agent. You adapt your behavior, reasoning st - Never present speculation as fact. If you don't know, say you don't know. - When a request seems ambiguous, investigate the cwd and project structure before asking for clarification. The answer is usually one command away. -# Tool & Skill Registry +# Workspace and paths + +The session working directory is authoritative. When a native tool requires an absolute path and the path is not known, run `pwd` first and use its exact result. Never guess or substitute `/home/oai`, `/root`, or another home directory. Native tool arguments receive resolved paths, not shell syntax or placeholders. Text such as `` or `` in examples must be replaced with the actual path first. Never pass angle-bracket placeholders literally. You have autonomous access to tools and skills. These are two different things: diff --git a/data/prompts/agent-coding.md b/data/prompts/agent-coding.md index d3a70e4..3e66a86 100644 --- a/data/prompts/agent-coding.md +++ b/data/prompts/agent-coding.md @@ -5,7 +5,13 @@ You are a coding agent. - Format output as markdown. - Short declarative sentences. No qualifiers. No weasel words. No filler. Say what needs to be said and stop. -# Code intelligence +# Workspace and paths + +- The current working directory is authoritative for repository work. +- Run `pwd` before supplying an absolute path to a tool when the path is not already known. +- Use the exact path returned by `pwd`. Do not guess a home directory. +- Never substitute `/home/oai`, `/root`, or another guessed path. +- Text such as `` or `` in examples is a placeholder. Replace it with the actual path before calling a tool; never pass the angle-bracket text literally. - Start unfamiliar repository work with `codebase_overview` when the workspace is large. - Use `code_outline` before reading a large source file in depth. diff --git a/data/prompts/agent-explorer.md b/data/prompts/agent-explorer.md index 61d3a3b..67fcc66 100644 --- a/data/prompts/agent-explorer.md +++ b/data/prompts/agent-explorer.md @@ -7,7 +7,12 @@ You do NOT edit files. You read, trace, and explain. - Format output as markdown. - Short declarative sentences. No qualifiers. No weasel words. No filler. Say what needs to be said and stop. -# How you work +# Workspace and paths + +- The session working directory is authoritative. +- Run `pwd` before using an absolute path that is not already known. +- Use the exact path returned by `pwd`; never guess `/home/oai`, `/root`, or another home directory. +- Text such as `` or `` in examples is a placeholder. Replace it with the actual path before calling a tool; never pass the angle-bracket text literally. - Use LSP aggressively: go-to-definition, find references, hover for types. Don't guess what something is when you can look it up. - Use `codebase_overview` to orient to an unfamiliar repository before deep reading. diff --git a/data/prompts/agent-navigator.md b/data/prompts/agent-navigator.md index de6dc3a..6e9ce11 100644 --- a/data/prompts/agent-navigator.md +++ b/data/prompts/agent-navigator.md @@ -7,7 +7,12 @@ You do NOT edit files. You use your tools to read, search, and understand — ne - Format output as markdown. - Short declarative sentences. No qualifiers. No weasel words. No filler. Say what needs to be said and stop. -# Code intelligence +# Workspace and paths + +- The session working directory is authoritative. +- Run `pwd` before using an absolute path that is not already known. +- Use the exact path returned by `pwd`; never guess `/home/oai`, `/root`, or another home directory. +- Text such as `` or `` in examples is a placeholder. Replace it with the actual path before calling a tool; never pass the angle-bracket text literally. - Use `codebase_overview` to orient to an unfamiliar repository. - Use `code_outline` and `code_symbols` to locate relevant declarations before editing. diff --git a/data/scripts/acme/README.md b/data/scripts/acme/README.md index 3b221fc..94da485 100644 --- a/data/scripts/acme/README.md +++ b/data/scripts/acme/README.md @@ -52,5 +52,5 @@ ln -s /path/to/ollie/data/scripts/acme/* ~/bin/ ## Example Tag ``` -/home/user/project/main.go Del Snarf Undo Put | AskFile Explain Fix Refactor +$HOME/project/main.go Del Snarf Undo Put | AskFile Explain Fix Refactor ``` diff --git a/data/tools/code_symbols.meta b/data/tools/code_symbols.meta index 147ff84..ea0a0dc 100644 --- a/data/tools/code_symbols.meta +++ b/data/tools/code_symbols.meta @@ -1,5 +1,5 @@ { "description": "Search Tree-sitter symbols across a codebase.", - "prompt": "## code_symbols\n\nSearch structural symbols across supported source files.\n\n**Args**: `[path, query]`\n\n```\ncode_symbols(path=\"/absolute/project\", query=\"Server\")\n```", + "prompt": "## code_symbols\n\nSearch structural symbols across supported source files.\n\n**Args**: `[path, query]`\n\n```\ncode_symbols(path=\"\", query=\"Server\")\n```", "args": {"type":"object","required":["path"],"properties":{"path":{"type":"string"},"query":{"type":"string"}}},"scope":"read" } diff --git a/data/tools/codebase_overview.meta b/data/tools/codebase_overview.meta index 9577e09..bbef268 100644 --- a/data/tools/codebase_overview.meta +++ b/data/tools/codebase_overview.meta @@ -1,6 +1,6 @@ { "description": "Render a Tree-sitter structural overview of a codebase.", - "prompt": "## codebase_overview\n\nParse supported source files and render declarations as Markdown.\n\n**Args**: `[path]`\n\n```\ncodebase_overview(path=\"/absolute/project\")\n```", + "prompt": "## codebase_overview\n\nParse supported source files and render declarations as Markdown.\n\n**Args**: `[path]`\n\n```\ncodebase_overview(path=\"\")\n```", "args": {"type":"object","required":["path"],"properties":{"path":{"type":"string","description":"Absolute or relative workspace path"}}}, "scope":"read" } diff --git a/data/tools/file_edit b/data/tools/file_edit index d77d599..9c37ea2 100755 --- a/data/tools/file_edit +++ b/data/tools/file_edit @@ -8,8 +8,8 @@ # **Args**: `path`, `old_string`, `new_string` (required); `replace_all` (optional) # # ``` -# file_edit(path="/abs/path", old_string="old text", new_string="new text") -# file_edit(path="/abs/path", old_string="old text", new_string="new text", replace_all="true") +# file_edit(path="", old_string="old text", new_string="new text") +# file_edit(path="", old_string="old text", new_string="new text", replace_all="true") # ``` # # **Constraints**: Absolute paths only. Errors if `old_string` matches multiple locations — add surrounding context to disambiguate, or use `replace_all=true`. diff --git a/data/tools/file_edit.meta b/data/tools/file_edit.meta index ee1f180..e4d9746 100644 --- a/data/tools/file_edit.meta +++ b/data/tools/file_edit.meta @@ -2,7 +2,7 @@ "description": "Replace text in a file. Has fuzzy matching (whitespace/indent flexible).", "outputFormat": "diff", "resetsCounter": true, - "prompt": "## file_edit\n\nReplace text in a file. Has fuzzy matching (whitespace/indent flexible).\n\n**Args**: `path`, `old_string`, `new_string` (required); `replace_all` (optional)\n\n```\nfile_edit(path=\"/abs/path\", old_string=\"old text\", new_string=\"new text\")\nfile_edit(path=\"/abs/path\", old_string=\"old text\", new_string=\"new text\", replace_all=\"true\")\n```\n\n**Constraints**: Absolute paths only. Errors if `old_string` matches multiple locations \u2014 add surrounding context to disambiguate, or use `replace_all=true`.", + "prompt": "## file_edit\n\nReplace text in a file. Has fuzzy matching (whitespace/indent flexible).\n\n**Args**: `path`, `old_string`, `new_string` (required); `replace_all` (optional)\n\n```\nfile_edit(path=\"\", old_string=\"old text\", new_string=\"new text\")\nfile_edit(path=\"\", old_string=\"old text\", new_string=\"new text\", replace_all=\"true\")\n```\n\n**Constraints**: Absolute paths only. Errors if `old_string` matches multiple locations \u2014 add surrounding context to disambiguate, or use `replace_all=true`.", "args": { "type": "object", "required": [ diff --git a/data/tools/file_glob b/data/tools/file_glob index 0060294..6df1be0 100755 --- a/data/tools/file_glob +++ b/data/tools/file_glob @@ -12,7 +12,7 @@ # - Second arg (optional): absolute search directory. Defaults to cwd. # # ``` -# file_glob(pattern="*.go", search_dir="/abs/search/dir") +# file_glob(pattern="*.go", search_dir="") # file_glob(pattern="**/*.go") # ``` # ollie:end diff --git a/data/tools/file_glob.meta b/data/tools/file_glob.meta index 948e10a..96a3ddc 100644 --- a/data/tools/file_glob.meta +++ b/data/tools/file_glob.meta @@ -1,6 +1,6 @@ { "description": "Find files by glob pattern, sorted by mtime (newest first).", - "prompt": "## file_glob\n\nFind files by glob pattern, sorted by mtime (newest first).\n\n**Args**: `[pattern]` or `[pattern, search_dir]`\n\n- First arg: glob pattern (e.g. `\"*.go\"`, `\"**/*.ts\"`).\n- Second arg (optional): absolute search directory. Defaults to cwd.\n\n```\nfile_glob(pattern=\"*.go\", search_dir=\"/abs/search/dir\")\nfile_glob(pattern=\"**/*.go\")\n```", + "prompt": "## file_glob\n\nFind files by glob pattern, sorted by mtime (newest first).\n\n**Args**: `[pattern]` or `[pattern, search_dir]`\n\n- First arg: glob pattern (e.g. `\"*.go\"`, `\"**/*.ts\"`).\n- Second arg (optional): absolute search directory. Defaults to cwd.\n\n```\nfile_glob(pattern=\"*.go\", search_dir=\"\")\nfile_glob(pattern=\"**/*.go\")\n```", "args": { "type": "object", "required": [ diff --git a/data/tools/file_grep b/data/tools/file_grep index 8feb1c1..70bb805 100755 --- a/data/tools/file_grep +++ b/data/tools/file_grep @@ -9,9 +9,9 @@ # **Args**: `pattern` (required), plus optional named params. # # ``` -# file_grep(pattern="pattern", path="/abs/dir") +# file_grep(pattern="pattern", path="") # file_grep(pattern="TODO", path="src/", glob="*.go", case_insensitive=true) -# file_grep(pattern="func main", path="/home/user/project") +# file_grep(pattern="func main", path="$PWD") # ``` # # - `path`: search directory (not a positional arg) diff --git a/data/tools/file_grep.meta b/data/tools/file_grep.meta index 9a79acf..766f621 100644 --- a/data/tools/file_grep.meta +++ b/data/tools/file_grep.meta @@ -1,6 +1,6 @@ { "description": "Search file contents with ripgrep. Capped at 50 matches by default.", - "prompt": "## file_grep\n\nSearch file contents with ripgrep. Capped at 50 matches by default.\n\n**Args**: `pattern` (required), plus optional named params.\n\n```\nfile_grep(pattern=\"pattern\", path=\"/abs/dir\")\nfile_grep(pattern=\"TODO\", path=\"src/\", glob=\"*.go\", case_insensitive=true)\nfile_grep(pattern=\"func main\", path=\"/abs/path\")\n```\n\n- `path`: search directory (not a positional arg)\n- `glob`: file glob filter\n- `case_insensitive`: boolean\n\n**Params**: `path`, `mode` (content|files_with_matches|count), `glob`, `type`, `case_insensitive`, `before`, `after`, `context`, `multiline`, `head`, `offset`.", + "prompt": "## file_grep\n\nSearch file contents with ripgrep. Capped at 50 matches by default.\n\n**Args**: `pattern` (required), plus optional named params.\n\n```\nfile_grep(pattern=\"pattern\", path=\"\")\nfile_grep(pattern=\"TODO\", path=\"src/\", glob=\"*.go\", case_insensitive=true)\nfile_grep(pattern=\"func main\", path=\"\")\n```\n\n- `path`: search directory (not a positional arg)\n- `glob`: file glob filter\n- `case_insensitive`: boolean\n\n**Params**: `path`, `mode` (content|files_with_matches|count), `glob`, `type`, `case_insensitive`, `before`, `after`, `context`, `multiline`, `head`, `offset`.", "args": { "type": "object", "required": [ diff --git a/data/tools/file_read b/data/tools/file_read index bd8f6fc..dfc29fb 100755 --- a/data/tools/file_read +++ b/data/tools/file_read @@ -14,9 +14,9 @@ # - `head`: read first N lines (alternative to start/end). # # ``` -# file_read(path="/abs/path") -# file_read(path="/abs/path", start="100", end="200") -# file_read(path="/abs/path", head="50") +# file_read(path="") +# file_read(path="", start="100", end="200") +# file_read(path="", head="50") # ``` # # - `start`/`end` are strings even though they represent numbers. diff --git a/data/tools/file_read.meta b/data/tools/file_read.meta index 18711fe..9157828 100644 --- a/data/tools/file_read.meta +++ b/data/tools/file_read.meta @@ -1,6 +1,6 @@ { "description": "Read a file with line numbers. Prefer segments over full reads.", - "prompt": "## file_read\n\nRead a file with line numbers. Prefer segments over full reads.\n\n**Args**: `path` (required), `start`, `end`, or `head`\n\n- `start`/`end`: 1-indexed line numbers, inclusive. Must be strings. Max segment: 2000 lines.\n- No start/end: reads up to 500 lines from line 1.\n- `head`: read first N lines (alternative to start/end).\n\n```\nfile_read(path=\"/abs/path\")\nfile_read(path=\"/abs/path\", start=\"100\", end=\"200\")\nfile_read(path=\"/abs/path\", head=\"50\")\n```\n\n- `start`/`end` are strings even though they represent numbers.\n- Use `head` as alternative to `start`/`end`.\n\n**Constraints**: Absolute paths only.", + "prompt": "## file_read\n\nRead a file with line numbers. Prefer segments over full reads.\n\n**Args**: `path` (required), `start`, `end`, or `head`\n\n- `start`/`end`: 1-indexed line numbers, inclusive. Must be strings. Max segment: 2000 lines.\n- No start/end: reads up to 500 lines from line 1.\n- `head`: read first N lines (alternative to start/end).\n\n```\nfile_read(path=\"\")\nfile_read(path=\"\", start=\"100\", end=\"200\")\nfile_read(path=\"\", head=\"50\")\n```\n\n- `start`/`end` are strings even though they represent numbers.\n- Use `head` as alternative to `start`/`end`.\n\n**Constraints**: Absolute paths only.", "args": { "type": "object", "required": [ diff --git a/data/tools/file_write b/data/tools/file_write index a40b681..dd2b642 100755 --- a/data/tools/file_write +++ b/data/tools/file_write @@ -8,7 +8,7 @@ # **Args**: `[path, content]` # # ``` -# file_write(path="/abs/path", content="file content here") +# file_write(path="", content="file content here") # ``` # # **Constraints**: Absolute paths only. Parent directory must exist. diff --git a/data/tools/file_write.meta b/data/tools/file_write.meta index 1696a2f..eec8140 100644 --- a/data/tools/file_write.meta +++ b/data/tools/file_write.meta @@ -2,7 +2,7 @@ "description": "Create or overwrite a file. Produces a unified diff.", "outputFormat": "diff", "resetsCounter": true, - "prompt": "## file_write\n\nCreate or overwrite a file. Produces a unified diff.\n\n**Args**: `[path, content]`\n\n```\nfile_write(path=\"/abs/path\", content=\"file content here\")\n```\n\n**Constraints**: Absolute paths only. Parent directory must exist.", + "prompt": "## file_write\n\nCreate or overwrite a file. Produces a unified diff.\n\n**Args**: `[path, content]`\n\n```\nfile_write(path=\"\", content=\"file content here\")\n```\n\n**Constraints**: Absolute paths only. Parent directory must exist.", "args": { "type": "object", "required": [ diff --git a/data/tools/image_read b/data/tools/image_read index cfb8fe8..ddba237 100755 --- a/data/tools/image_read +++ b/data/tools/image_read @@ -8,7 +8,7 @@ # Read an image file. Returns an image content block for the model. # # ``` -# image_read(path="/abs/path/image.png") +# image_read(path="") # ``` # ollie:end diff --git a/data/tools/image_read.meta b/data/tools/image_read.meta index 7bfe20d..78bc031 100644 --- a/data/tools/image_read.meta +++ b/data/tools/image_read.meta @@ -1,6 +1,6 @@ { "description": "Read an image file. Returns an image content block for the model.", - "prompt": "## image_read\n\nRead an image file. Returns an image content block for the model.\n\n```\nimage_read(path=\"/abs/path/image.png\")\n```", + "prompt": "## image_read\n\nRead an image file. Returns an image content block for the model.\n\n```\nimage_read(path=\"\")\n```", "args": { "type": "object", "required": [ diff --git a/data/tools/subagent_spawn b/data/tools/subagent_spawn index 883c5a3..9626f9e 100755 --- a/data/tools/subagent_spawn +++ b/data/tools/subagent_spawn @@ -8,7 +8,7 @@ # # ``` # subagent_spawn(prompt="fix the failing tests in auth/") -# subagent_spawn(prompt="implement the login page", cwd="/home/user/project", model="sonnet") +# subagent_spawn(prompt="implement the login page", cwd="$PWD", model="sonnet") # ``` # # Multiple subagent_spawn calls in the same turn run in parallel automatically. diff --git a/data/tools/subagent_spawn.meta b/data/tools/subagent_spawn.meta index 82ff98d..751a721 100644 --- a/data/tools/subagent_spawn.meta +++ b/data/tools/subagent_spawn.meta @@ -1,6 +1,6 @@ { "description": "Spawn a sub-agent with a task. Blocks until done, returns the reply.", - "prompt": "## subagent_spawn\n\nSpawn a sub-agent with a task. Blocks until the sub-agent completes and returns its reply.\nThe sub-agent gets its own context window and tool access. It is destroyed when done.\n\n```\nsubagent_spawn(prompt=\"fix the failing tests in auth/\")\nsubagent_spawn(prompt=\"implement the login page\", cwd=\"/home/user/project\", model=\"sonnet\")\n```\n\nMultiple subagent_spawn calls in the same turn run in parallel automatically.", + "prompt": "## subagent_spawn\n\nSpawn a sub-agent with a task. Blocks until the sub-agent completes and returns its reply.\nThe sub-agent gets its own context window and tool access. It is destroyed when done.\n\n```\nsubagent_spawn(prompt=\"fix the failing tests in auth/\")\nsubagent_spawn(prompt=\"implement the login page\", cwd=\"$PWD\", model=\"sonnet\")\n```\n\nMultiple subagent_spawn calls in the same turn run in parallel automatically.", "scope": "read", "tier": "hot", "args": { diff --git a/doc/9p.md b/doc/9p.md index 416451b..4bc2ee4 100644 --- a/doc/9p.md +++ b/doc/9p.md @@ -29,7 +29,7 @@ ollie-9p read session/myproj/agent/coding/chat echo "name=myproj" | ollie-9p write session/new # Create an agent -echo "name=coding cwd=/home/user/project" | ollie-9p write session/myproj/agent/new +echo "name=coding cwd=$PWD" | ollie-9p write session/myproj/agent/new # Submit a prompt echo "fix the bug in main.go" | ollie-9p write session/myproj/agent/coding/prompt @@ -41,7 +41,7 @@ ollie-9p read session/myproj/agent/coding/chat ollie-9p read session/myproj/agent/coding/statewait # Spawn a sub-agent (blocks until done, returns reply) -printf 'cwd=/home/user/project\nprompt=fix the failing tests\n' \ +printf 'cwd=%s\nprompt=fix the failing tests\n' "$PWD" \ | ollie-9p rdwr session/myproj/agent/new ``` diff --git a/doc/remote-execution.md b/doc/remote-execution.md index 3a6576e..83dcffc 100644 --- a/doc/remote-execution.md +++ b/doc/remote-execution.md @@ -27,7 +27,7 @@ flowchart TB subgraph Remote["Remote Host (via SSH)"] REMOTE_BIN["ollie-remote"] EXEC["toolsrv.Server\n- landrun sandbox\n- shell execution\n- tool definitions\n- file I/O"] - CWD["Working directory:\n/home/user/project/"] + CWD["Working directory:\n$HOME/project/"] SANDCFG["Sandbox config:\nremote host's landrun"] end @@ -138,11 +138,11 @@ A session targeting a remote host: ```bash # Via 9P -printf 'cwd=/home/user/project\nremote=devbox\n' > $OLLIE/session/new +printf 'cwd=%s\nremote=devbox\n' "$PWD" > $OLLIE/session/new # Via D-Bus dbus-send ... org.ollie.SessionManager.CreateSession \ - string:"/home/user/project" string:"" string:"" string:"default" \ + string:"$HOME/project" string:"" string:"" string:"default" \ string:"" string:"devbox" # remote host ``` diff --git a/doc/resources/multi-agent.md b/doc/resources/multi-agent.md index 3359de1..1d65f76 100644 --- a/doc/resources/multi-agent.md +++ b/doc/resources/multi-agent.md @@ -59,7 +59,7 @@ Session creation can be split into two phases for advanced orchestration scenarios: 1. **Create empty session**: `echo "name=my-session" | ollie-9p rdwr session/new` -2. **Add agent**: `echo "cwd=/home/user agent=default backend=openai model=gpt-4o" | ollie-9p rdwr session/my-session/agent/new` +2. **Add agent**: `echo "cwd=$HOME agent=default backend=openai model=gpt-4o" | ollie-9p rdwr session/my-session/agent/new` Empty sessions (`Core=nil`) are valid — they appear in `session/idx`, have no running agent, and can be killed or renamed. This enables pre-provisioning