<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vương Nguyên Khang</title>
    <description>The latest articles on DEV Community by Vương Nguyên Khang (@vng_nguynkhang_7550b0).</description>
    <link>https://dev.to/vng_nguynkhang_7550b0</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4122072%2F2a2d7053-ddb0-4d8b-9d97-10b01993ffeb.png</url>
      <title>DEV Community: Vương Nguyên Khang</title>
      <link>https://dev.to/vng_nguynkhang_7550b0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vng_nguynkhang_7550b0"/>
    <language>en</language>
    <item>
      <title>Do Coding Agents Really Need Unrestricted Shell Access?</title>
      <dc:creator>Vương Nguyên Khang</dc:creator>
      <pubDate>Sat, 12 Sep 2026 12:22:32 +0000</pubDate>
      <link>https://dev.to/vng_nguynkhang_7550b0/do-coding-agents-really-need-unrestricted-shell-access-4b2o</link>
      <guid>https://dev.to/vng_nguynkhang_7550b0/do-coding-agents-really-need-unrestricted-shell-access-4b2o</guid>
      <description>&lt;p&gt;&lt;em&gt;Exploring a bounded repository capability layer with MCP, AST/LSP code intelligence, guarded writes, and Git context.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Coding agents need access to a repository. They need to read files, search for implementations, follow definitions, change source, and inspect the resulting diff. A general-purpose shell can support all of those tasks.&lt;/p&gt;

&lt;p&gt;It can also do almost everything else available to the host account.&lt;/p&gt;

&lt;p&gt;That is the trade-off behind &lt;a href="https://github.com/BoxBoxmari/my-pi" rel="noopener noreferrer"&gt;my-pi&lt;/a&gt;, an open-source experiment in exposing a narrower repository capability surface through the Model Context Protocol (MCP).&lt;/p&gt;

&lt;p&gt;The question is not whether shells are bad. Shells are universal, composable, mature, and already present on most developer machines. The narrower question is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For ordinary repository work, how much useful capability can we expose without making arbitrary command execution the default interface?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;my-pi is an attempt to test that question in code. It is an alpha project, not a claim that one interface fits every coding workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shell is an excellent abstraction, and a broad authority boundary
&lt;/h2&gt;

&lt;p&gt;When an agent needs to find code, a shell gives it rg, git, language tooling, package managers, build systems, and arbitrary scripts. That generality is why shell-based agents are so effective.&lt;/p&gt;

&lt;p&gt;But the interface is not really just “repository access.” It is general command execution with the authority of the host process.&lt;/p&gt;

&lt;p&gt;That distinction matters when we decide what an agent should be allowed to do by default. A coding task may need five broad classes of action:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;inspect an authorized workspace;&lt;/li&gt;
&lt;li&gt;read and search files;&lt;/li&gt;
&lt;li&gt;understand code structure and symbols;&lt;/li&gt;
&lt;li&gt;perform a bounded mutation;&lt;/li&gt;
&lt;li&gt;inspect repository state and diffs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A shell can do all five. It does not naturally stop at those five.&lt;/p&gt;

&lt;p&gt;The thesis behind my-pi is that these operations are valuable enough to expose directly for some workflows, with the boundary visible in the protocol and runtime rather than hidden in a prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with explicit workspace authority
&lt;/h2&gt;

&lt;p&gt;The command-line server accepts an explicit workspace:&lt;/p&gt;

&lt;p&gt;my-pi-mcp --workspace /path/to/your/project&lt;/p&gt;

&lt;p&gt;It can also use MY_PI_WORKSPACE_ROOT. If neither is present, the server refuses to start unless the caller explicitly opts into the current directory with --allow-cwd.&lt;/p&gt;

&lt;p&gt;This changes the initial contract. The agent is not silently granted access to whichever directory happened to be the process working directory. The runtime has a root against which workspace paths are resolved and revalidated.&lt;/p&gt;

&lt;p&gt;That is less convenient than starting a shell in an arbitrary directory. It is also easier to inspect and explain.&lt;/p&gt;

&lt;p&gt;Explicit authority does not make the host trustworthy by magic. The process still has the operating-system permissions of its account. The benefit is narrower: the repository boundary is part of the server configuration instead of an assumption shared only by the caller and the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read-only is a useful state, not a broken state
&lt;/h2&gt;

&lt;p&gt;The default my-pi profile is read-only. A normal session can inspect workspace metadata, read bounded file windows, search, query AST structure, request code-intelligence operations when their backends are available, and inspect Git status or diffs.&lt;/p&gt;

&lt;p&gt;Mutation and language-server process startup require an explicit trusted profile:&lt;/p&gt;

&lt;p&gt;my-pi-mcp \&lt;br&gt;
  --workspace /path/to/your/project \&lt;br&gt;
  --security-profile trusted&lt;/p&gt;

&lt;p&gt;The distinction is useful even before making a security argument. Review, triage, code explanation, and repository exploration often do not require writes. A read-only session gives those tasks a meaningful operating mode instead of forcing every caller to choose between a full shell and no repository context.&lt;/p&gt;

&lt;p&gt;The word “trusted” is deliberate. It describes an explicit authority decision about the workspace. It is not a universal security guarantee. The &lt;a href="https://github.com/BoxBoxmari/my-pi/blob/main/docs/SECURITY_MODEL.md" rel="noopener noreferrer"&gt;security model&lt;/a&gt; still matters, as do the host process, dependencies, operating-system permissions, and the code being inspected.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small surface can be more legible than a large one
&lt;/h2&gt;

&lt;p&gt;The stable alpha surface advertises 13 core tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;workspace_info&lt;/li&gt;
&lt;li&gt;fs_read, fs_write, fs_patch, fs_stat&lt;/li&gt;
&lt;li&gt;search&lt;/li&gt;
&lt;li&gt;ast_search&lt;/li&gt;
&lt;li&gt;lsp_status, lsp_symbols, lsp_navigate, lsp_diagnostics&lt;/li&gt;
&lt;li&gt;vcs_status, vcs_diff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The server also reports capability availability. That detail is important: discoverable does not mean that every backend is active in every environment. AST and LSP operations depend on their language tooling and runtime dependencies, while the filesystem, search, and VCS paths have a different set of requirements.&lt;/p&gt;

&lt;p&gt;The point of listing the tools is not to claim that 13 is the perfect number. It is to make the interface inspectable. A caller can reason about the categories, their risk class, and their failure modes without first learning every command that a shell might launch.&lt;/p&gt;

&lt;p&gt;The implementation is also not pretending that the underlying ecosystem disappears. For example, a VCS backend may use Git for read-only repository operations. The boundary under discussion is the authority exposed to the agent, not a promise that every internal dependency is rewritten from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filesystem access is necessary, but it is not code intelligence
&lt;/h2&gt;

&lt;p&gt;A repository is more than a tree of text files. A coding agent may need to answer questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where is this function defined?&lt;/li&gt;
&lt;li&gt;Which files reference this symbol?&lt;/li&gt;
&lt;li&gt;Which implementation matches this structure?&lt;/li&gt;
&lt;li&gt;What diagnostics does the language server report?&lt;/li&gt;
&lt;li&gt;What changed relative to the current Git revision?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Shell commands can reconstruct many of those answers. my-pi exposes a few higher-level categories directly.&lt;/p&gt;

&lt;p&gt;ast_search is intended for structure-aware search through supported languages. LSP tools provide status, diagnostics, symbols, and navigation when a compatible language server is available. Git tools provide bounded status and diff context.&lt;/p&gt;

&lt;p&gt;This separation does not make a model understand code automatically. It does make the requested operation more explicit. “Find a function-shaped node” and “find a string in every file” are different questions, even if a shell can be used to approximate both.&lt;/p&gt;

&lt;p&gt;The availability boundary is part of the contract. A tool that cannot run because a language server is absent should be reported as unavailable, not presented as if a successful semantic result had been produced.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mutation should acknowledge stale context
&lt;/h2&gt;

&lt;p&gt;One ordinary failure mode in agentic coding is stale state.&lt;/p&gt;

&lt;p&gt;An agent reads a file, reasons about a change, and writes several seconds later. In the meantime, the file may have changed because of another agent, the developer, a formatter, or an earlier tool call. Blind overwrite semantics turn old reasoning into a silent lost update.&lt;/p&gt;

&lt;p&gt;my-pi uses content preconditions for filesystem mutation. A read produces a content hash. An overwrite or patch carries the hash that the caller observed. The runtime compares it with the current file before publishing the change.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;/p&gt;

&lt;p&gt;read file&lt;br&gt;
   |&lt;br&gt;
receive fingerprint&lt;br&gt;
   |&lt;br&gt;
reason about change&lt;br&gt;
   |&lt;br&gt;
write or patch with expected_hash&lt;br&gt;
   |&lt;br&gt;
accept if the state matches&lt;br&gt;
reject if the state is stale&lt;/p&gt;

&lt;p&gt;For an existing file, fs_write requires expected_hash. fs_patch requires it as well. A missing or mismatched precondition fails before the mutation is committed. This is a small compare-and-swap style primitive, not a complete solution to concurrent development.&lt;/p&gt;

&lt;p&gt;It does not prevent two agents from making incompatible edits when they both start from the same version. It does prevent the second writer from silently overwriting a version it never observed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sensitive paths should be policy decisions, not prompt suggestions
&lt;/h2&gt;

&lt;p&gt;The runtime has a sensitive-path policy covering patterns such as .env*, .aws/, .ssh/, credential-like files, and key material. The policy is evaluated before a file is read or traversed into by the relevant capability.&lt;/p&gt;

&lt;p&gt;That is a different boundary from telling a model:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please do not read secrets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Prompt guidance can influence behavior. It is not enforcement. A runtime policy can reject a path before its content is allocated into the tool result and model context.&lt;/p&gt;

&lt;p&gt;This still requires honest scope. Sensitive-path matching is not a proof that every secret has a conventional filename. It is one policy layer in a local runtime. A user who changes the policy, grants trusted access, or runs the host with excessive operating-system privileges can change the practical risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  The strongest case for unrestricted shell access
&lt;/h2&gt;

&lt;p&gt;The best argument against a bounded interface is not that it is difficult to implement. It is that the shell already solves the general problem.&lt;/p&gt;

&lt;p&gt;A shell is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;universal;&lt;/li&gt;
&lt;li&gt;composable;&lt;/li&gt;
&lt;li&gt;familiar to developers;&lt;/li&gt;
&lt;li&gt;capable of invoking any compiler, linter, test runner, package manager, or script;&lt;/li&gt;
&lt;li&gt;easier to extend than a fixed tool catalog.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many coding agents are already good at shell use. Giving them a new capability protocol introduces schemas, error mapping, maintenance, and compatibility work. A narrow interface earns its place only if its explicit boundaries create practical value that justifies this friction.&lt;/p&gt;

&lt;p&gt;For my-pi, the proposed advantages are explicit workspace authority, a meaningful read-only profile, content-preconditioned mutation, pre-read sensitive-path policy, structural search, semantic navigation, and bounded Git context.&lt;/p&gt;

&lt;p&gt;Whether those advantages are enough is an empirical question. The answer will depend on the workflow. An agent that must run a custom build graph, invoke a database migration, debug a live process, or use an unfamiliar repository script may reasonably reach for a shell immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this model is deliberately weaker
&lt;/h2&gt;

&lt;p&gt;my-pi does not expose arbitrary command execution as one of its core repository tools. That means it is a poor fit for some tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;running tests with project-specific orchestration;&lt;/li&gt;
&lt;li&gt;invoking build scripts and package managers;&lt;/li&gt;
&lt;li&gt;starting or inspecting databases;&lt;/li&gt;
&lt;li&gt;using dynamic debuggers;&lt;/li&gt;
&lt;li&gt;operating deployment tools;&lt;/li&gt;
&lt;li&gt;composing one-off repository automation;&lt;/li&gt;
&lt;li&gt;investigating a system whose important state lives outside the workspace.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are not edge cases in software development. They are part of the reason the shell remains attractive.&lt;/p&gt;

&lt;p&gt;The bounded model is therefore not “better than the shell” in the abstract. It is a candidate interface for a subset of repository work. Its success depends on whether that subset is large enough to justify a separate contract and whether the missing operations can be added without recreating arbitrary execution through a growing collection of escape hatches.&lt;/p&gt;

&lt;h2&gt;
  
  
  What my-pi does not claim
&lt;/h2&gt;

&lt;p&gt;It does not claim that a bounded MCP surface is automatically secure.&lt;/p&gt;

&lt;p&gt;It does not claim that shell access is always wrong.&lt;/p&gt;

&lt;p&gt;It does not claim that the current alpha replaces a full coding environment.&lt;/p&gt;

&lt;p&gt;It does not claim that tool count is a proxy for usefulness. Thirteen poorly designed tools would be worse than a shell; one missing operation can make an otherwise sensible workflow frustrating.&lt;/p&gt;

&lt;p&gt;The project is a test of a design boundary. The repository contains the implementation, compatibility notes, and security model so that the claims can be challenged against code rather than treated as product copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I want to learn
&lt;/h2&gt;

&lt;p&gt;I am interested in concrete counterexamples and failures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which repository operation is missing before this interface becomes useful to you?&lt;/li&gt;
&lt;li&gt;Which tool is redundant because an existing shell workflow is clearer?&lt;/li&gt;
&lt;li&gt;Does content-preconditioned mutation prevent real failures in long-running or multi-agent sessions?&lt;/li&gt;
&lt;li&gt;Is read-only code intelligence valuable on its own?&lt;/li&gt;
&lt;li&gt;At what point does a bounded surface become more friction than simply giving the agent a terminal?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the strongest answer is “the shell is already the right abstraction,” that is useful evidence. If a narrower surface is sufficient for a meaningful class of workflows, that is useful evidence too.&lt;/p&gt;

&lt;p&gt;The goal is to test the trade-off rather than assume the answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;General-purpose shell access is an extraordinarily powerful interface for coding agents. That is precisely why it is worth asking what should be exposed by default.&lt;/p&gt;

&lt;p&gt;my-pi explores one alternative: an explicit workspace boundary with repository-specific filesystem, code-intelligence, mutation, and Git capabilities exposed through MCP. The design is early, intentionally narrow, and dependent on the environment in which it runs.&lt;/p&gt;

&lt;p&gt;The useful question is not whether bounded access defeats shell access. It is where the boundary should sit for a real workflow.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What task would make you immediately abandon this bounded capability model and reach for unrestricted shell access instead?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Repository: &lt;a href="https://github.com/BoxBoxmari/my-pi" rel="noopener noreferrer"&gt;github.com/BoxBoxmari/my-pi&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I maintain the open-source my-pi project discussed here. I built it partly to test the capability-boundary ideas in this article.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
