{"id":49904646,"url":"https://github.com/vixcpp/agent","last_synced_at":"2026-05-16T10:03:07.793Z","repository":{"id":358049043,"uuid":"1239622374","full_name":"vixcpp/agent","owner":"vixcpp","description":"Local-first AI agent runtime for Vix.cpp.","archived":false,"fork":false,"pushed_at":"2026-05-15T12:57:44.000Z","size":54,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-15T13:35:04.134Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vixcpp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-15T09:19:00.000Z","updated_at":"2026-05-15T12:57:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vixcpp/agent","commit_stats":null,"previous_names":["vixcpp/agent"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/vixcpp/agent","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vixcpp%2Fagent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vixcpp%2Fagent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vixcpp%2Fagent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vixcpp%2Fagent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vixcpp","download_url":"https://codeload.github.com/vixcpp/agent/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vixcpp%2Fagent/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33098340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T04:41:52.686Z","status":"ssl_error","status_checked_at":"2026-05-16T04:41:52.009Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-16T10:03:05.853Z","updated_at":"2026-05-16T10:03:07.785Z","avatar_url":"https://github.com/vixcpp.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Vix AI Agent\n\nLocal-first AI agent module for Vix.cpp.\n\n`vix::ai::agent` provides a small, explicit, and production-oriented foundation for building AI-powered developer tools in C++.\n\nIt is designed around:\n\n- local model providers\n- safe workspace access\n- controlled tools\n- structured errors\n- run history\n- conservative caching\n- explicit configuration\n\nThe current stable public API is:\n\n```cpp\nAgent::run(const AgentRequest \u0026request)\n```\n\nOther helpers such as `chat()`, `analyze()`, `explain()`, or `run_with_tools()` are intentionally not exposed yet as stable APIs.\n\n## Public header\n\n```cpp\n#include \u003cvix/ai/agent/agent.hpp\u003e\n```\n\nThis umbrella header exposes the public agent API:\n\n```cpp\n#include \u003cvix/ai/agent/Agent.hpp\u003e\n#include \u003cvix/ai/agent/AgentConfig.hpp\u003e\n#include \u003cvix/ai/agent/AgentConfigLoader.hpp\u003e\n#include \u003cvix/ai/agent/AgentConfigValidator.hpp\u003e\n#include \u003cvix/ai/agent/AgentError.hpp\u003e\n#include \u003cvix/ai/agent/AgentRequest.hpp\u003e\n#include \u003cvix/ai/agent/AgentResponse.hpp\u003e\n#include \u003cvix/ai/agent/AgentResult.hpp\u003e\n#include \u003cvix/ai/agent/AgentRunStore.hpp\u003e\n#include \u003cvix/ai/agent/AgentRunTimer.hpp\u003e\n#include \u003cvix/ai/agent/AgentWorkspace.hpp\u003e\n```\n\n## Basic usage\n\n```cpp\n#include \u003cvix/ai/agent/agent.hpp\u003e\n#include \u003cvix/print.hpp\u003e\n\nint main()\n{\n  vix::ai::agent::AgentConfig config;\n\n  config.provider = \"ollama\";\n  config.model = \"llama3\";\n  config.model_url = \"http://127.0.0.1:11434\";\n\n  config.allow_file_read = true;\n  config.allow_process = false;\n  config.allow_file_write = false;\n\n  vix::ai::agent::Agent agent(config);\n\n  vix::ai::agent::AgentRequest request;\n\n  request.input = \"Explain this project in simple words.\";\n  request.workspace = \".\";\n  request.mode = vix::ai::agent::AgentRequestMode::Analyze;\n\n  request.allow_tools = true;\n  request.allow_file_read = true;\n  request.allow_process = false;\n  request.allow_file_write = false;\n\n  auto result = agent.run(request);\n\n  if (!result)\n  {\n    vix::print(\"Agent error:\", result.error().message());\n    return 1;\n  }\n\n  vix::print(result.value().text);\n\n  return 0;\n}\n```\n\n## Design goals\n\nVix AI Agent is designed to be:\n\n- local-first by default\n- safe by default\n- explicit about permissions\n- deterministic where possible\n- observable through run history\n- cache-aware but conservative\n- usable from C++ without hiding behavior\n\nThe agent does not silently read or modify files outside the workspace.\n\n## Current status\n\nCurrent stable surface:\n\n```\nAgent::run(...)\n```\n\nCurrent internal features:\n\n- local Ollama provider through `vix::net::http`\n- model provider abstraction\n- workspace scanner\n- safe file reader\n- controlled tool registry\n- `file.read` tool\n- `command.run` tool with allowlist\n- run history\n- conservative model response cache\n- structured errors through `vix::error::Result\u003cT\u003e`\n\n## Architecture\n\n```\nagent/\n├── Agent\n├── AgentConfig\n├── AgentConfigLoader\n├── AgentConfigValidator\n├── AgentRequest\n├── AgentResponse\n├── AgentRunStore\n├── AgentWorkspace\n├── crypto/\n│   ├── AgentFingerprint\n│   └── AgentId\n├── model/\n│   ├── ModelProvider\n│   ├── ModelRequest\n│   ├── ModelResponse\n│   └── OllamaProvider\n├── tools/\n│   ├── Tool\n│   ├── ToolCall\n│   ├── ToolRegistry\n│   ├── ToolResult\n│   ├── FileReadTool\n│   └── CommandTool\n└── workspace/\n    ├── FileReader\n    ├── FileScanPolicy\n    └── ProjectScanner\n```\n\n## Main concepts\n\n### Agent\n\n`Agent` is the main orchestrator.\n\nIt receives an `AgentRequest`, prepares the workspace, builds model context, optionally executes controlled tools, and returns an `AgentResponse`.\n\n```cpp\nvix::ai::agent::Agent agent(config);\n\nauto result = agent.run(request);\n```\n\n### AgentConfig\n\n`AgentConfig` controls the agent runtime.\n\n```cpp\nvix::ai::agent::AgentConfig config;\n\nconfig.provider = \"ollama\";\nconfig.model = \"llama3\";\nconfig.model_url = \"http://127.0.0.1:11434\";\n\nconfig.timeout_ms = 30'000;\nconfig.tool_timeout_ms = 30'000;\n\nconfig.max_files = 2'000;\nconfig.max_file_size = 512 * 1024;\nconfig.max_tool_output = 20'000;\nconfig.max_context_chars = 120'000;\nconfig.max_tool_rounds = 3;\n\nconfig.offline = true;\n\nconfig.allow_file_read = true;\nconfig.allow_process = false;\nconfig.allow_file_write = false;\n\nconfig.use_cache = true;\nconfig.cache_ttl_ms = 5 * 60 * 1000;\n\nconfig.persist_memory = true;\n```\n\n### AgentRequest\n\n`AgentRequest` represents one user request.\n\n```cpp\nvix::ai::agent::AgentRequest request;\n\nrequest.input = \"Explain this project.\";\nrequest.workspace = \".\";\nrequest.mode = vix::ai::agent::AgentRequestMode::Analyze;\n\nrequest.allow_tools = true;\nrequest.allow_file_read = true;\nrequest.allow_process = false;\nrequest.allow_file_write = false;\nrequest.use_cache = true;\n```\n\n### AgentResponse\n\n`AgentResponse` contains the final text, metadata, model information, run id, cache status, and tool summaries.\n\n```cpp\nauto result = agent.run(request);\n\nif (result)\n{\n  const auto \u0026response = result.value();\n\n  vix::print(\"run:\", response.run_id);\n  vix::print(\"provider:\", response.provider);\n  vix::print(\"model:\", response.model);\n  vix::print(\"from cache:\", response.from_cache);\n  vix::print(response.text);\n}\n```\n\n## Request modes\n\n`AgentRequestMode` controls the high-level behavior of the request.\n\n```cpp\nrequest.mode = vix::ai::agent::AgentRequestMode::Run;\nrequest.mode = vix::ai::agent::AgentRequestMode::Analyze;\nrequest.mode = vix::ai::agent::AgentRequestMode::Explain;\nrequest.mode = vix::ai::agent::AgentRequestMode::Chat;\n```\n\n| Mode | Purpose |\n|------|---------|\n| `Run` | Normal single request |\n| `Analyze` | Analyze a workspace or project |\n| `Explain` | Explain something without modifying files |\n| `Chat` | Chat-style interaction |\n\n## Local-first model provider\n\nThe default provider is Ollama.\n\n```cpp\nconfig.provider = \"ollama\";\nconfig.model = \"llama3\";\nconfig.model_url = \"http://127.0.0.1:11434\";\n```\n\nThe current `OllamaProvider` targets:\n\n```\nPOST /api/generate\n```\n\nExample local setup:\n\n```bash\nollama serve\nollama pull llama3\n```\n\nThen run your Vix AI Agent program.\n\n## Safety controls\n\nThe agent is explicit about local capabilities.\n\n```cpp\nconfig.allow_file_read = true;\nconfig.allow_process = false;\nconfig.allow_file_write = false;\n```\n\nPer request, permissions can be restricted further:\n\n```cpp\nrequest.allow_tools = true;\nrequest.allow_file_read = true;\nrequest.allow_process = false;\nrequest.allow_file_write = false;\n```\n\nThe effective permission is restrictive.\n\nIf the global config disables a capability, the request cannot enable it.\n\nFor example, this fails:\n\n```cpp\nconfig.allow_process = false;\nrequest.allow_process = true;\n```\n\n## Workspace boundary\n\nAll file operations are resolved through `AgentWorkspace`.\n\nThe workspace protects the agent from reading outside the project root.\n\nIt rejects:\n\n- empty paths\n- parent directory escapes\n- paths outside the workspace\n- invalid workspace roots\n\nDefault internal directories:\n\n```\n.vix/agent/memory\n.vix/agent/cache\n.vix/agent/runs\n.vix/agent/logs\n```\n\n## File scanning policy\n\n`FileScanPolicy` controls what the agent may scan or read.\n\nIt rejects common generated or unsafe paths such as:\n\n```\n.git\n.vix\n.cache\n.idea\n.vscode\nbuild\nbuild-ninja\nbuild-release\nbuild-debug\ncmake-build-debug\ncmake-build-release\nnode_modules\nvendor\ndist\nout\ntarget\n__pycache__\n```\n\nIt also rejects:\n\n- hidden files\n- unsupported extensions\n- files larger than `config.max_file_size`\n\nCommon allowed extensions include:\n\n```\n.c\n.cc\n.cpp\n.cxx\n.h\n.hh\n.hpp\n.hxx\n.cmake\n.txt\n.md\n.json\n.yaml\n.yml\n.toml\n.js\n.jsx\n.ts\n.tsx\n.vue\n.py\n.rs\n.go\n.java\n.php\n.rb\n.sh\n.zsh\n.bash\n.html\n.css\n.scss\n.sql\n```\n\n## Tool system\n\nThe agent has a controlled tool system.\n\nCurrent tools:\n\n| Tool | Purpose |\n|------|---------|\n| `file.read` | Read a safe text file inside the workspace |\n| `command.run` | Run an allowed local command inside the workspace |\n\nTools are registered in `ToolRegistry`.\n\nThe agent can execute model-requested tool calls through a controlled loop:\n\n```\nmodel request\ntool calls\ntool execution\ntool results\nfinal model response\n```\n\n### File read tool\n\nTool name:\n\n```\nfile.read\n```\n\nExpected arguments:\n\n```json\n{\n  \"path\": \"src/main.cpp\"\n}\n```\n\nThe path is resolved through `AgentWorkspace` and checked by `FileScanPolicy`.\n\n### Command tool\n\nTool name:\n\n```\ncommand.run\n```\n\nExpected arguments:\n\n```json\n{\n  \"program\": \"vix\",\n  \"args\": [\"build\"],\n  \"working_directory\": \".\"\n}\n```\n\n`command.run` is disabled by default.\n\nTo enable it:\n\n```cpp\nconfig.allow_process = true;\nconfig.allowed_programs = {\n    \"vix\",\n    \"cmake\",\n    \"ninja\",\n    \"git\",\n    \"ls\",\n    \"cat\",\n    \"echo\"\n};\n```\n\nPrograms not present in `allowed_programs` are rejected.\n\nDangerous programs are also blocked:\n\n```\nrm\nrmdir\nmv\ndd\nmkfs\nshutdown\nreboot\npoweroff\nsudo\nsu\n```\n\nThe command working directory must stay inside the workspace.\n\n### Tool limits\n\nImportant tool-related limits:\n\n```cpp\nconfig.tool_timeout_ms = 30'000;\nconfig.max_tool_output = 20'000;\nconfig.max_tool_rounds = 3;\n```\n\nCurrent status:\n\n- `max_tool_output` is enforced by `CommandTool`\n- `max_tool_rounds` is enforced by `Agent`\n- `tool_timeout_ms` is part of the API and validation\n- real process timeout will be enforced when `vix::process` supports command timeouts\n\n## Run history\n\nWhen `persist_memory` is enabled, the agent stores local run history.\n\n```cpp\nconfig.persist_memory = true;\n```\n\nRun history is written under:\n\n```\n.vix/agent/runs/\u003crun_id\u003e/\n```\n\nA run may include:\n\n```\nrun.json\nprompt.txt\nmodel_response.json\ntools.json\nresponse.json\nresponse.txt\nerror.json\n```\n\nThis makes local debugging, auditing, and replay support easier to build later.\n\n## Cache\n\nWhen `use_cache` is enabled, the agent can reuse safe cached model responses.\n\n```cpp\nconfig.use_cache = true;\nconfig.cache_ttl_ms = 5 * 60 * 1000;\n```\n\nThe first cache implementation is conservative:\n\n- only successful responses are cached\n- responses involving tools are not cached\n- cache is stored locally under `.vix/agent/cache`\n- cache keys are based on provider, model, prompt, and context fingerprint\n\n## Environment configuration\n\n`AgentConfigLoader` can load configuration from environment variables.\n\n```cpp\nauto config =\n    vix::ai::agent::AgentConfigLoader::from_environment();\n```\n\nDefault prefix:\n\n```\nVIX_AGENT_\n```\n\nSupported variables include:\n\n```\nVIX_AGENT_PROVIDER\nVIX_AGENT_MODEL\nVIX_AGENT_MODEL_URL\nVIX_AGENT_MEMORY_DIR\nVIX_AGENT_CACHE_DIR\nVIX_AGENT_RUNS_DIR\nVIX_AGENT_LOGS_DIR\nVIX_AGENT_TIMEOUT_MS\nVIX_AGENT_MAX_FILES\nVIX_AGENT_MAX_FILE_SIZE\nVIX_AGENT_MAX_TOOL_OUTPUT\nVIX_AGENT_MAX_CONTEXT_CHARS\nVIX_AGENT_OFFLINE\nVIX_AGENT_ALLOW_PROCESS\nVIX_AGENT_ALLOW_FILE_READ\nVIX_AGENT_ALLOW_FILE_WRITE\nVIX_AGENT_USE_CACHE\nVIX_AGENT_PERSIST_MEMORY\n```\n\nExample:\n\n```bash\nexport VIX_AGENT_PROVIDER=ollama\nexport VIX_AGENT_MODEL=llama3\nexport VIX_AGENT_MODEL_URL=http://127.0.0.1:11434\nexport VIX_AGENT_ALLOW_PROCESS=false\n```\n\nThen:\n\n```cpp\nauto config = vix::ai::agent::AgentConfigLoader::from_environment();\nvix::ai::agent::Agent agent(config);\n```\n\n## Configuration validation\n\nUse `AgentConfigValidator` to validate a config before running the agent.\n\n```cpp\nvix::ai::agent::AgentConfig config;\n\nauto err = vix::ai::agent::AgentConfigValidator::validate(config);\n\nif (err)\n{\n  vix::print(\"Invalid config:\", err.message());\n  return 1;\n}\n```\n\nThe agent also validates its configuration at runtime before executing a request.\n\n## Custom model provider\n\nYou can inject your own provider by implementing `ModelProvider`.\n\n```cpp\nclass MyProvider final : public vix::ai::agent::ModelProvider\n{\npublic:\n  [[nodiscard]] std::string_view name() const noexcept override\n  {\n    return \"my-provider\";\n  }\n\n  [[nodiscard]] bool local() const noexcept override\n  {\n    return true;\n  }\n\n  [[nodiscard]] vix::ai::agent::AgentResult\u003cbool\u003e available() const override\n  {\n    return true;\n  }\n\n  [[nodiscard]] vix::ai::agent::AgentResult\u003cvix::ai::agent::ModelResponse\u003e generate(\n      const vix::ai::agent::ModelRequest \u0026request) override\n  {\n    vix::ai::agent::ModelResponse response;\n\n    response.text = \"Hello from my provider\";\n    response.model = request.model;\n    response.provider = \"my-provider\";\n    response.status = vix::ai::agent::ModelResponseStatus::Completed;\n\n    return response;\n  }\n};\n```\n\nUse it with `Agent`:\n\n```cpp\nauto provider = std::make_shared\u003cMyProvider\u003e();\n\nvix::ai::agent::Agent agent(config, provider);\n```\n\n## Custom tools\n\nCreate a tool by implementing `Tool`.\n\n```cpp\nclass EchoTool final : public vix::ai::agent::Tool\n{\npublic:\n  [[nodiscard]] std::string_view name() const noexcept override\n  {\n    return \"test.echo\";\n  }\n\n  [[nodiscard]] std::string_view description() const noexcept override\n  {\n    return \"Echo test tool.\";\n  }\n\n  [[nodiscard]] vix::ai::agent::AgentResult\u003cvix::ai::agent::ToolResult\u003e run(\n      const vix::ai::agent::ToolCall \u0026call) override\n  {\n    return vix::ai::agent::ToolResult::success(\n        call.id,\n        \"test.echo\",\n        \"echo\");\n  }\n};\n```\n\nRegister it:\n\n```cpp\nvix::ai::agent::Agent agent(config);\n\nauto err = agent.tools().add(std::make_shared\u003cEchoTool\u003e());\n\nif (err)\n{\n  vix::print(\"Tool error:\", err.message());\n}\n```\n\n## Error handling\n\nThe agent uses:\n\n```cpp\nvix::ai::agent::AgentResult\u003cT\u003e\n```\n\nwhich is an alias around:\n\n```cpp\nvix::error::Result\u003cT\u003e\n```\n\nExample:\n\n```cpp\nauto result = agent.run(request);\n\nif (!result)\n{\n  const auto \u0026err = result.error();\n\n  vix::print(\"error:\", err.message());\n  return 1;\n}\n\nvix::print(result.value().text);\n```\n\nAgent-specific errors include:\n\n```\nempty_input\ninvalid_workspace\npath_outside_workspace\nmodel_unavailable\nmodel_request_failed\nmodel_response_invalid\ntool_not_found\ntool_not_allowed\ntool_failed\ntool_timeout\nmemory_unavailable\nmemory_write_failed\nmemory_read_failed\nconfig_invalid\ninternal_failure\n```\n\n## Testing\n\nFrom the module directory:\n\n```bash\ncd ~/vixcpp/vix/modules/agent\ncmake --build build-ninja\n./build-ninja/vix_ai_agent_tests\n```\n\nCurrent test areas:\n\n- `AgentConfig`\n- `AgentConfigValidator`\n- `AgentWorkspace`\n- `ProjectScanner`\n- `FileScanPolicy`\n- `FileReader`\n- `ToolRegistry`\n- `CommandTool`\n- `AgentRun`\n- `AgentRunStore`\n- `AgentCache`\n- `AgentPublicApi`\n\n## Build\n\nFrom the module directory:\n\n```bash\ncd ~/vixcpp/vix/modules/agent\nvix build --build-target all -v\n```\n\nFrom the Vix root:\n\n```bash\ncd ~/vixcpp/vix\nvix build --build-target all -v\n```\n\n## Example with Ollama\n\n```cpp\n#include \u003cvix/ai/agent/agent.hpp\u003e\n#include \u003cvix/print.hpp\u003e\n\nint main()\n{\n  vix::ai::agent::AgentConfig config;\n\n  config.provider = \"ollama\";\n  config.model = \"llama3\";\n  config.model_url = \"http://127.0.0.1:11434\";\n\n  config.allow_file_read = true;\n  config.allow_process = false;\n  config.allow_file_write = false;\n\n  config.use_cache = true;\n  config.persist_memory = true;\n\n  vix::ai::agent::Agent agent(config);\n\n  vix::ai::agent::AgentRequest request;\n\n  request.workspace = \".\";\n  request.input = \"Explain what this project does.\";\n  request.mode = vix::ai::agent::AgentRequestMode::Analyze;\n\n  request.allow_tools = true;\n  request.allow_file_read = true;\n  request.allow_process = false;\n  request.allow_file_write = false;\n\n  auto result = agent.run(request);\n\n  if (!result)\n  {\n    vix::print(\"Agent failed:\", result.error().message());\n    return 1;\n  }\n\n  vix::print(result.value().text);\n\n  return 0;\n}\n```\n\n## License\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvixcpp%2Fagent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvixcpp%2Fagent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvixcpp%2Fagent/lists"}