Agentic Work

TensorSharp.AgentHost turns a local model response into a bounded generate → inspect → run → repair → answer loop. It can load Agent Skills only when they are needed, work with files through five built-in code tools, run checks inside an OS sandbox, and return finished artifacts to an ordinary CLI, Web UI, Ollama, or OpenAI client.

What happens in one turn

  1. Advertise capabilities cheaply

    TensorSharp puts only each reachable skill's name and description in the prompt. A selected skill is preferred and made reachable; selection does not load its instructions.

  2. Load instructions on demand

    When a tool-capable model decides a skill applies, it calls skills_read(skill, "SKILL.md"). TensorSharp answers that built-in call in process, appends the result to the same conversation, and generates again.

  3. Do the work

    If the operator enabled --code-exec, the model can inspect, edit, create, patch, and test files in a request or chat workspace. Skill scripts can participate too, but only under their separate execution opt-in.

  4. Return an ordinary answer

    The client receives the final completion rather than TensorSharp's internal tool calls. A caller's own tools are never executed by TensorSharp; those calls are returned normally for the caller to service.

🎯

Current scope is one model and one in-process tool loop. TensorSharp does not spawn multiple agents or delegate to subagents, and it has no interactive approval queue before each command. The operator grants or withholds skills, script execution, code execution, networking, and installation when the CLI or server starts; an internal tool then runs under that policy or refuses.

TensorAgent on iPhone and iPad

TensorAgent packages this local chat and agent experience as a .NET MAUI iOS/iPadOS app. The engine is statically linked as an iOS .xcframework and uses ggml_metal on physical devices. The app shares the host-neutral chat pipeline (TensorSharp.Chat) with the CLI and server, but serves the UI through an in-process loopback server because iOS has no ASP.NET Core runtime pack. What it shares is the API, not the document: the phone gets its own page, laid out for a thumb rather than a mouse and a wide window, bound to the same WebUiChatService and SkillsService routes.

Models download to the device with resume and SHA-256 verification; conversations survive app restarts; photos, camera, video, files, and dictation use the same chat attachment flow. Since iOS cannot start child processes, TensorAgent's shell, Python, and JavaScript integrations are runtime-backed and report their limits explicitly.

Three constraints a phone imposes that a desktop does not, and what the app does about each:

ConstraintWhat the app does
The screen goes away mid-answerGeneration belongs to a host-side manager, not to the WebView — WebKit suspends a page whose view left the window. A turn continues while the app is backgrounded and the page re-attaches to it on return.
The first message of a launch pays for the whole shared prefixThe state at the end of the prompt every chat shares is checkpointed to disk per model and restored at admission on the next launch. Measured on iPhone 17 Pro Max with Qwen3.5 9B: a 54 s cold first message becomes a 1.2 s warm-up and a ~0.6 s first message.
iOS jetsam kills without a stack or a messageThe engine's memory policy is sized against what jetsam charges — wired file pages count against the device, not the process — so caches start small and grow, a request reserves a bounded reply, and a memory warning releases what only serves the next request's speed.

See the TensorAgent README for build, simulator, device, and verification instructions.

Agent Skills and progressive disclosure

A skill is a directory containing a required SKILL.md plus any scripts, references, and assets its instructions need. TensorSharp follows the Agent Skills specification and can load published skill repositories without rewriting their layout.

pdf/
├── SKILL.md
├── scripts/
│   └── extract_tables.py
├── references/
│   └── forms.md
└── assets/
    └── template.pdf
TierWhat reaches the modelWhen
Metadataname + descriptionUp front for selected and discoverable skills. This is the normal prompt cost.
InstructionsThe complete SKILL.md bodyOnly after the model activates it with skills_read(skill, "SKILL.md").
Bundled filesReferences, scripts, and assetsPaths and sizes are indexed; content is fetched only through skills_read, paged at 48 KB.

The normal metadata block uses about 2% of the context window, clamped to roughly 1,024–10,000 tokens. The old behavior that inlined every selected body is off by default. A model family that cannot carry and parse tool declarations has no opportunity to call skills_read, so TensorSharp instead inlines selected skill bodies within a bounded fallback budget and does not advertise skills it cannot load.

The built-in skill tools are skills_list and skills_read. A third tool, skills_run, appears only with --skills-allow-exec. Script execution is off by default and remains separate from model-authored code execution.

Five code tools, off by default

--code-exec adds a patch-first coding surface. It does not require a skill, and merely installing or selecting a skill does not turn it on.

ToolPurposeImportant bound
read_fileRead real workspace bytes with line numbers.Bounded output; paths stay inside the workspace.
edit_fileReplace one exact string in one file.Refuses missing or ambiguous matches instead of guessing.
write_fileCreate a file or deliberately replace it whole.Confined to the workspace and reports rewrite scope.
apply_patchCreate, update, rename, or delete several files by anchored hunks.Atomic: all hunks apply or none do.
shellRun tests, commands, and generated programs.Timeout and output caps; sandbox-or-refuse on supported hosts.

Failures are designed to be repairable. A diagnostic that identifies a regular source file in the workspace returns a bounded source excerpt and asks for the smallest exact edit before rerunning. Syntax checks, missing-import installation when allowed, and installed-library API hints reduce avoidable model rounds.

Workspace lifetime and artifacts

SurfaceWorkspace lifetimeResult
CLI / interactive chatPersistent for the process or chat session.One tool call can inspect or repair files written by an earlier call.
Bundled Web UIPersistent for that Web chat session.Live writing/running activity, bounded output, and generated-file download chips.
OpenAI and Ollama HTTP chatOne private workspace across every internal tool round in that request; deleted when the response finishes.Repairs work within a request, while separate requests remain stateless.
skills_run without code executionFresh per-call scratch directory, deleted on return.Scripts do not accidentally share state.

When code execution is enabled, a skill script shares the same request/chat workspace as the five code tools. The server copies produced files into its bounded artifact store; the Web UI exposes safe download links, and artifact responses are sent as attachments with content sniffing disabled.

Sandbox-or-refuse security model

Enabling execution is an operator decision, not a request field. On macOS and Linux, model-authored commands and opted-in skill scripts run with a workspace write boundary, an unreadable home directory, a scrubbed environment, and network denied by default. Paths are also checked in process before the OS sandbox is entered.

PlatformModel-authored codeSkill scripts
macOSsandbox-exec; refuses if confinement is unavailable.Default --skills-sandbox required; sandboxed or refused.
LinuxRequires bwrap 0.12.0 or newer; otherwise refuses.The same safe bwrap requirement under the default required mode.
WindowsNo filesystem/network sandbox is implemented. --code-exec-unconfined is required and intentionally grants the process's file and network reach.A job object bounds the process tree but not files or sockets. Default required refuses; --skills-sandbox preferred is the explicit weaker opt-in.
⚠️

Sandboxed does not mean a disposable VM. macOS deliberately retains shared /private/tmp compatibility and some local Unix IPC. Seatbelt restrictions pass to children and ordinary process groups are stopped, but a deliberately detached child can outlive the request; every tool result reports that gap. Linux shares parts of the host network namespace even while IP networking is denied. Every reported platform gap matters. Do not enable unconfined execution on a server other people can reach.

Network and package installation are separate opt-ins

OptionDefaultWhat it grants
--code-exec-allow-networkOffUnrestricted host IP networking for every model-authored command, including LAN/loopback services. It is not domain-filtered.
--skills-allow-networkOffNetwork for opted-in bundled skill scripts only. It does not affect shell.
--code-exec-allow-installOffHost-performed recognized pip/npm installs. The host reads and validates package names, uses prebuilt wheels / disabled npm scripts, and removes the install from the model's command.

--code-exec-packages, --code-exec-install-index, and --code-exec-install-domains constrain the host installer. They are not a security boundary after unrestricted command networking is enabled, because generated code can download an artifact directly. The script and code network switches are intentionally independent.

Start an agentic session

Skills can be used without executing code:

dotnet run --project TensorSharp.Cli -c Release -- \
  --model models/model.gguf --backend ggml_metal \
  --skills-dir ./skills --skill pdf -i

Add the five code tools explicitly. This example keeps both command networking and package installation off:

dotnet run --project TensorSharp.Cli -c Release -- \
  --model models/model.gguf --backend ggml_metal \
  --skills-dir ./skills --skill pdf --code-exec -i

Or host the same loop for the Web UI and compatible APIs:

dotnet run --project TensorSharp.Server.Host -c Release -- \
  --model models/model.gguf --backend ggml_cuda \
  --skills-dir ./skills --code-exec

# Browser UI: http://localhost:5000/
# Liveness:   http://localhost:5000/health

On Linux, install bwrap 0.12.0 or newer first. On Windows, code execution remains unavailable unless the operator deliberately adds --code-exec-unconfined. Do not copy that Windows escape hatch onto a shared server.

Use skills from an ordinary HTTP client

The server must be started with a skills registry. A client then selects skills on the normal chat request; TensorSharp services its own skill/code calls internally and returns the completed response.

{
  "model": "local",
  "messages": [
    { "role": "user", "content": "Extract the tables and summarize the findings." }
  ],
  "skills": ["pdf"],
  "skills_discovery": false,
  "stream": true
}

skills_discovery defaults to true. Code execution has no per-request enable field: the operator either started the host with --code-exec or the five tools are absent. The agent loop allows 8 internal rounds by default, or 24 when code execution is enabled; --skills-max-rounds sets an explicit 1–64 bound.

Model-family limits

The in-process loop requires a model family that can both carry tool declarations and parse tool calls. Families without that round trip receive selected skill instructions inline as a fallback, but are not offered the five code tools. TensorSharp logs the limitation rather than silently pretending code execution is available.