<?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: zhayujie</title>
    <description>The latest articles on DEV Community by zhayujie (@zhayujie).</description>
    <link>https://dev.to/zhayujie</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%2F3988119%2F71051261-781e-4018-8853-e318bc032844.png</url>
      <title>DEV Community: zhayujie</title>
      <link>https://dev.to/zhayujie</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zhayujie"/>
    <language>en</language>
    <item>
      <title>Designing an agent-friendly CLI</title>
      <dc:creator>zhayujie</dc:creator>
      <pubDate>Fri, 17 Jul 2026 07:12:32 +0000</pubDate>
      <link>https://dev.to/zhayujie/designing-an-agent-friendly-cli-4g9n</link>
      <guid>https://dev.to/zhayujie/designing-an-agent-friendly-cli-4g9n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;As agents mature, more and more products will need to serve two kinds of users at once: humans and agents. A CLI is one of the easier forms for an agent to call, and in the future many products may want to ship their own CLI to expose their core capabilities to agents. This post walks through the design of a CLI we recently open-sourced for a platform product, covering six areas: language choice, login and authorization, command and flag design, skills, distribution, and security.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why a CLI
&lt;/h2&gt;

&lt;p&gt;An agent can reach an external capability in roughly three ways: calling an API directly, going through MCP, or running a command in a terminal. All three are ultimately wrappers over the same remote interfaces, but a CLI has two advantages for agents. First, almost every general-purpose agent already ships with a Bash tool (Codex, Claude Code, CowAgent, OpenClaw, and so on), so there is no MCP server for the provider to stand up. Second, the CLI packs auth, parameter assembly, pagination, and error handling into the command itself: the agent does not have to construct HTTP requests, and it does not need the full API reference in context — a short command description is enough to decide what to run, which saves tokens and reduces mistakes.&lt;/p&gt;

&lt;p&gt;What changes is the shape of the user. A CLI used to be driven by a developer sitting at a terminal; now there is also an agent running a "read output, decide, run the next command" loop. The two have quite different needs, and serving both well becomes a design problem in itself. The rest of this post uses a real CLI as an example and walks through the key decisions along the way. The overall picture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.link-ai.tech%2Fdoc%2Fagent-friendly-cli-desion-overview-en.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.link-ai.tech%2Fdoc%2Fagent-friendly-cli-desion-overview-en.png" width="800" alt="CLI design overview" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Language
&lt;/h2&gt;

&lt;p&gt;A few hard requirements shaped the language choice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single file, no runtime dependency&lt;/strong&gt;: an agent's environment is unpredictable — a local machine, a Docker container, a remote Linux box — and you cannot assume the right Node or Python version is installed. Ideally you download one binary and it just runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy cross-compilation&lt;/strong&gt;: it needs to cover macOS / Linux / Windows × amd64 / arm64 from a single codebase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast startup&lt;/strong&gt;: an agent calls commands frequently, so a compiled language is preferable to an interpreter that pays cold-start cost each time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A quick comparison of the candidates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Node / TypeScript&lt;/strong&gt;: great ecosystem and fast to write, but it depends on a Node runtime on the target machine, and bundling to a single file produces large artifacts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt;: same runtime and version headaches, and distribution is a real pain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rust&lt;/strong&gt;: single binary, good performance, meets every requirement, but development and compile speed are slower.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go&lt;/strong&gt;: a single static binary, zero dependencies with &lt;code&gt;CGO_ENABLED=0&lt;/code&gt;, solid cross-compilation, millisecond startup, and reasonable development speed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We ended up choosing Go, with Cobra as the CLI framework for command parsing and routing. Because the artifact is a plain binary, a single GoReleaser config can produce the npm package, Homebrew cask, and GitHub release together. There is no universal answer here — it depends on your team's stack — but if agents are the primary users, a language that compiles to a zero-dependency single binary should come first. How smoothly you can distribute it directly decides whether an agent can install it on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Login and Authorization
&lt;/h2&gt;

&lt;p&gt;The simplest way to authorize a CLI is to have the user paste an API key. The problems are obvious: an API key is usually long-lived, carries full permissions, and sits in plaintext on disk. If it leaks, everything is exposed, and there is no way to scope it per operation. For a CLI that agents call automatically and that manages real resources, that "one key opens every door" model is too risky.&lt;/p&gt;

&lt;p&gt;So we use the OAuth 2.0 Device Authorization Grant (device flow). The user logs in and grants scopes in a browser, and the CLI receives a short-lived, refreshable, scope-limited access token that the server can revoke at any time. The flow has three steps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.link-ai.tech%2Fdoc%2F6acc8411-5bd8-4536-b8af-b4ccc76aed7c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.link-ai.tech%2Fdoc%2F6acc8411-5bd8-4536-b8af-b4ccc76aed7c.png" width="800" alt="Device flow diagram" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is another common OAuth variant where the CLI starts a temporary local HTTP server to catch the browser redirect (tools like &lt;code&gt;gh&lt;/code&gt; and &lt;code&gt;gcloud&lt;/code&gt; do this). That does not work well for agents, which often run on a server with no browser, no display, and no open ports. The device flow lets the authorization happen in a browser on any machine, while the CLI side only kicks it off and polls. Two parts of this are worth calling out.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Two-phase polling
&lt;/h3&gt;

&lt;p&gt;When a human logs in, the CLI can open the browser and block on polling until the user is done. But an agent runs a "run a command, read the result, decide the next step" loop. If a single tool call both prints the login link and then blocks on polling, the link never makes it back to the user through the model, and the whole session stalls.&lt;/p&gt;

&lt;p&gt;So the agent login is split into two phases. &lt;strong&gt;The first phase returns immediately.&lt;/strong&gt; The JSON it returns includes the verification URL, the device code, and a &lt;code&gt;next_action&lt;/code&gt; field that tells the agent exactly what to run next:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;linkai auth login &lt;span class="nt"&gt;--no-wait&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The second phase polls&lt;/strong&gt;, blocking for at most a bounded number of seconds before returning. If the user has not finished, the agent simply runs the same command again on its next tool call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;linkai auth login &lt;span class="nt"&gt;--device-code&lt;/span&gt; &amp;lt;code&amp;gt; &lt;span class="nt"&gt;--wait&lt;/span&gt; 60 &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--wait&lt;/code&gt; flag distinguishes the two users: leaving it off (blocking until the device code expires) gives the interactive human flow; passing &lt;code&gt;--wait&lt;/code&gt; switches to the bounded polling path an agent needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 The authorization page
&lt;/h3&gt;

&lt;p&gt;The authorization page is where the user actually interacts and makes a decision, so it needs to make three things clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which account / device / CLI is requesting authorization&lt;/li&gt;
&lt;li&gt;which permissions are being requested, listing the scopes per module so the user can see exactly what the CLI is being granted&lt;/li&gt;
&lt;li&gt;a note that they can return to the terminal once done, since the terminal is still polling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.link-ai.tech%2Fdoc%2F20260715211014.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.link-ai.tech%2Fdoc%2F20260715211014.png" width="800" alt="CLI authorization page" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Commands and Flags
&lt;/h2&gt;

&lt;p&gt;For the same command, a developer wants a clean table and streaming output, while an agent wants a single parseable, structured response. A few details follow from that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.link-ai.tech%2Fdoc%2F20260715193006.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.link-ai.tech%2Fdoc%2F20260715193006.png" width="800" alt="CLI terminal output" height="649"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 JSON output
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;--json&lt;/code&gt; is a global flag that makes any command emit structured JSON. With it, the agent's skill only has to say "always pass &lt;code&gt;--json&lt;/code&gt;," and every command returns output the agent can parse reliably.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Streaming vs. non-streaming
&lt;/h3&gt;

&lt;p&gt;For commands that talk to a model, humans like the streaming (SSE) typewriter effect. But when an agent calls the command through Bash, the output gets piped, and streaming breaks the reply into fragments that are hard to parse — the agent wants the full reply in one piece.&lt;/p&gt;

&lt;p&gt;Rather than forcing the user to remember &lt;code&gt;--stream&lt;/code&gt; / &lt;code&gt;--no-stream&lt;/code&gt;, the default follows the environment: streaming in a terminal, non-streaming when the output is piped or redirected (the typical agent case), and always non-streaming with &lt;code&gt;--json&lt;/code&gt;. An explicit flag overrides all of this.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Dry run for writes
&lt;/h3&gt;

&lt;p&gt;Destructive or mutating commands support &lt;code&gt;--dry-run&lt;/code&gt;, which prints the request that would be sent instead of actually sending it. The agent can check the parameters before it commits to the operation, which also adds a layer of safety.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 Output separation and exit codes
&lt;/h3&gt;

&lt;p&gt;Results go to stdout; everything procedural goes to stderr. Progress notes, update notices, and confirmation prompts are all things that, if mixed into stdout, would break the agent's JSON parsing. With them on stderr, the agent only has to read stdout.&lt;/p&gt;

&lt;p&gt;Exit codes are also structured so the agent can decide whether to retry or stop: 0 success, 1 generic error, 2 bad arguments, 3 auth/permission, 4 network. On a permission error (exit 3), the message includes the command to fix it (for example &lt;code&gt;linkai auth login --scope "..."&lt;/code&gt;), so the agent re-triggers authorization instead of retrying blindly.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Skill Design
&lt;/h2&gt;

&lt;p&gt;The CLI wraps a set of interfaces in commands; the next problem is helping the agent understand how to call them correctly. Probing with &lt;code&gt;--help&lt;/code&gt; over and over is too costly, so the CLI ships a companion skill — a manual written for the agent.&lt;/p&gt;

&lt;p&gt;The skill structure is kept as flat as possible: a single &lt;code&gt;SKILL.md&lt;/code&gt; as the entry point, with per-module command details under a &lt;code&gt;references/&lt;/code&gt; directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;skills/linkai-cli/
├── SKILL.md          # entry point: global notes + module overview + decision flow
└── references/       # details per module: auth / install / admin ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Installed into an agent, this is a single directory. The idea is to have the agent read the main skill first and only dig into &lt;code&gt;references/&lt;/code&gt; when it needs module-level detail. Some CLIs install every sub-module as its own separate skill, which is not ideal: the agent loses a global view of the CLI, and a large number of sub-skills inflates its context.&lt;/p&gt;

&lt;p&gt;The skill is embedded into the binary with &lt;code&gt;go:embed&lt;/code&gt; and locked to the CLI version, so the docs never drift from what the binary actually supports. A &lt;code&gt;skill install&lt;/code&gt; command handles installation in one step.&lt;/p&gt;

&lt;p&gt;One more detail: the main &lt;code&gt;SKILL.md&lt;/code&gt; includes a short install section. When an agent gets the skill first — for example by downloading it directly — it can still follow those instructions to install the CLI binary.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Distribution and Updates
&lt;/h2&gt;

&lt;p&gt;Distribution matters a lot for usability, and there are two things to distribute: the CLI binary and the agent skill. The goal is that one sentence to an agent is enough for it to get set up. It helps to support several channels so developers and agents on any platform can find one that works:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;npm&lt;/td&gt;
&lt;td&gt;&lt;code&gt;npm i -g linkai-cli&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;install script&lt;/td&gt;
&lt;td&gt;&lt;code&gt;curl -fsSL .../install.sh&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Homebrew&lt;/td&gt;
&lt;td&gt;&lt;code&gt;brew install .../linkai&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;&lt;code&gt;go install .../linkai-cli@latest&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub Release&lt;/td&gt;
&lt;td&gt;download the binary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On a machine with Node, npm is the most convenient path: it hides the OS and CPU differences, picks the right binary, and puts it on PATH. The install script is a better fit for dependency-free environments; besides downloading the CLI, it also drops the skill into the skill directories of common agents (Codex, Claude Code, Cursor, OpenClaw, CowAgent, and others).&lt;/p&gt;

&lt;p&gt;To let an agent set everything up from one sentence, a clear install guide (&lt;code&gt;install.md&lt;/code&gt;) matters too. It writes out the full from-scratch steps, so the user can just hand the agent a line like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read &lt;a href="https://cdn.link-ai.tech/cli/install.md" rel="noopener noreferrer"&gt;https://cdn.link-ai.tech/cli/install.md&lt;/a&gt; and follow it to install the CLI and skill, then start using it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.link-ai.tech%2Fdoc%2F20260715204933.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.link-ai.tech%2Fdoc%2F20260715204933.png" width="800" alt="Installing the CLI inside an agent" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Updates are an extension of distribution, done in two layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Passive notice&lt;/strong&gt;: on startup the CLI fetches and caches the latest version in the background, and prints a one-line notice to stderr on exit (mainly for the human at the terminal, so it never pollutes the stdout an agent parses).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active update&lt;/strong&gt;: &lt;code&gt;update&lt;/code&gt; detects how the CLI was originally installed, calls the matching package manager to upgrade, and syncs the skill afterward.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Security
&lt;/h2&gt;

&lt;p&gt;Login and authorization are only the first layer. A few more things matter in the agent case:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Least privilege.&lt;/strong&gt; Scopes use a &lt;code&gt;resource:action&lt;/code&gt; format (for example &lt;code&gt;app:read&lt;/code&gt;, &lt;code&gt;db:write&lt;/code&gt;). By default only read and content-generation scopes are granted; mutating and destructive operations must be requested explicitly. Each command declares the scope it needs and it is checked centrally, so even if an agent slips, it cannot go beyond what the user granted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Token storage.&lt;/strong&gt; On macOS the credential goes into the system keychain; on other platforms it is stored in a file (mode &lt;code&gt;0600&lt;/code&gt;). The token is an opaque, server-revocable token rather than a self-decoding JWT, and logout revokes it on the server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Device binding.&lt;/strong&gt; Every request carries a device ID, and the server binds the token to that device, which limits abuse if a token leaks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Dangerous-character filtering.&lt;/strong&gt; Content an agent handles may come from untrusted sources (web pages, external input) and can carry invisible attack characters — Bidi overrides, zero-width characters, ANSI escapes — that alter command meaning or spoof the terminal. The CLI rejects these on input and strips them on output.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;The way you design a CLI is quite different from designing a GUI product, and even among CLIs, one for agents differs from one for developers. To summarize the main ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Language&lt;/strong&gt;: prefer a compiled language that produces a single binary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Login&lt;/strong&gt;: use the device flow so authorization happens in a browser, and support phased login for agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commands and flags&lt;/strong&gt;: give humans a clean view and agents structured data, tolerate extra flags, allow dry runs, and return next-step hints on error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skill&lt;/strong&gt;: as a manual for the agent, keep it a single directory with a flat structure to lower both the learning and context cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distribution&lt;/strong&gt;: support multiple channels and add an install guide an agent can follow on its own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: beyond login, cover least privilege, credential protection, device binding, and filtering of untrusted content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is specific to CLIs. Structured output, tolerant error handling, a companion skill, smooth distribution, and least privilege apply just as well to APIs, SDKs, and other products that serve both humans and agents.&lt;/p&gt;

&lt;p&gt;Open-source project referenced in this post: &lt;a href="https://github.com/MinimalFuture/linkai-cli" rel="noopener noreferrer"&gt;github.com/MinimalFuture/linkai-cli&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>A Five-Layer Self-Evolution Mechanism for AI Agents</title>
      <dc:creator>zhayujie</dc:creator>
      <pubDate>Wed, 17 Jun 2026 11:50:24 +0000</pubDate>
      <link>https://dev.to/zhayujie/a-five-layer-self-evolution-mechanism-for-ai-agents-2on6</link>
      <guid>https://dev.to/zhayujie/a-five-layer-self-evolution-mechanism-for-ai-agents-2on6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Self-evolution is a core module of the Agent Harness. With it, an Agent can keep improving across long-running tasks: refining its own skills, recording user feedback and preferences, and reviewing its own work to keep getting better. This post walks through the architecture and engineering behind a five-layer self-evolution mechanism, drawn from a real open-source agent implementation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Overall Design
&lt;/h2&gt;

&lt;p&gt;Self-evolution is not just about making an Agent remember things. It is about letting the Agent improve and repair itself through continuous feedback. The mechanism divides into five layers by depth: recording information, retaining information, taking action, consolidating, and self-rewriting. Each depth differs in what it improves, when it triggers, and how far its effects reach.&lt;/p&gt;

&lt;p&gt;Two questions drive the implementation: &lt;strong&gt;when evolution is triggered&lt;/strong&gt; and &lt;strong&gt;what gets improved&lt;/strong&gt;. The full mechanism is built from five layers, each mapping to a different depth of evolution: basic memory and knowledge maintenance, smart context summarization, post-session review, dream-based memory consolidation, and source-code self-update. The overall architecture:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45lgm0rrq06cjlqh9gqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F45lgm0rrq06cjlqh9gqx.png" alt="Overview of the five-layer self-evolution mechanism" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it improves&lt;/th&gt;
&lt;th&gt;When it triggers&lt;/th&gt;
&lt;th&gt;Depth&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Basic memory &amp;amp; knowledge maintenance&lt;/td&gt;
&lt;td&gt;Memory / knowledge / prompts&lt;/td&gt;
&lt;td&gt;During each conversation&lt;/td&gt;
&lt;td&gt;Record&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Smart context summarization&lt;/td&gt;
&lt;td&gt;Memory&lt;/td&gt;
&lt;td&gt;When context overflows&lt;/td&gt;
&lt;td&gt;Retain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Post-session review&lt;/td&gt;
&lt;td&gt;Skills / memory / prompts / tasks&lt;/td&gt;
&lt;td&gt;After a session goes idle&lt;/td&gt;
&lt;td&gt;Act&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dream-based memory consolidation&lt;/td&gt;
&lt;td&gt;Long-term memory&lt;/td&gt;
&lt;td&gt;Daily, on schedule&lt;/td&gt;
&lt;td&gt;Consolidate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source-code self-update&lt;/td&gt;
&lt;td&gt;Code&lt;/td&gt;
&lt;td&gt;Passive / active trigger&lt;/td&gt;
&lt;td&gt;Self-rewrite&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  1. Basic Memory and Knowledge Maintenance
&lt;/h2&gt;

&lt;p&gt;The most basic layer of self-evolution happens inside every conversation. Guided by the model's tool-use decisions and the system prompt, the Agent judges whether a conversation contains anything worth keeping, then uses built-in tools to write preferences, decisions, facts, and lessons into long-term memory, reusable knowledge into the knowledge base, and anything about its own persona or operating rules into prompt files.&lt;/p&gt;

&lt;p&gt;These three kinds of information differ in target and timing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt;: persisted as files in the workspace, split into core memory and daily memory. Core memory (&lt;code&gt;MEMORY.md&lt;/code&gt;) holds long-lived facts such as user preferences and key decisions, and is injected into the system prompt of every conversation, so it must stay concise. Daily memory (&lt;code&gt;memory/YYYY-MM-DD.md&lt;/code&gt;) records key events and conversation summaries by day, and is loaded only when the Agent uses its memory-retrieval tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge base&lt;/strong&gt;: stored as Markdown source files in the workspace with vectorized data in the database, organized by topic and cross-linked into a knowledge graph. When a conversation involves research or learning, the Agent proactively files the organized knowledge here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts&lt;/strong&gt;: persona (&lt;code&gt;AGENT.md&lt;/code&gt;), rules (&lt;code&gt;RULE.md&lt;/code&gt;), and user info (&lt;code&gt;USER.md&lt;/code&gt;) can also be edited mid-conversation. All of them load into the system prompt, letting the Agent adjust its own settings based on feedback and fit the user's habits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pag59rudi648us6kf83.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7pag59rudi648us6kf83.png" alt="Example of writing memory and knowledge during a conversation" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Example above: in a single message the user states a preference and asks the Agent to research a new concept. While answering, the Agent writes the preference into memory and files the organized material into the knowledge base.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Smart Context Summarization
&lt;/h2&gt;

&lt;p&gt;The previous layer is about how to remember key information. This one is about how the Agent avoids losing information as it evolves. Context is short-term memory, with configurable limits on both turn count and token length. When those limits are exceeded, the system does not simply drop old messages. It distills and summarizes the important parts and writes them into daily memory. The compression runs in four steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Truncate oversized tool results&lt;/strong&gt;: the first and cheapest step. When a single tool result in a past turn (say, a search that returned tens of thousands of lines) exceeds a threshold, only the head and tail are kept along with a short elision note; the current in-progress turn is left untouched. This step is pure string handling with no model call, and it often absorbs most of the growth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trim by complete turns&lt;/strong&gt;: when the turn limit is exceeded, the system trims the oldest half &lt;strong&gt;using a full conversation turn as the smallest unit&lt;/strong&gt;, rather than deleting messages one by one. This keeps each tool call's input and result paired, so the model is never left with a tool call that has no matching result. The trimmed content is not discarded: an LLM organizes, distills, and summarizes it, then writes it into the day's daily memory for persistence and injects the summary back at the start of the retained messages, so the model can still pick up the thread after the raw detail is gone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compress by token budget&lt;/strong&gt;: if the token limit is still exceeded after trimming turns, a finer pass runs. When there are only a few turns, each turn is compressed to text (keeping the user's first question and the Agent's final reply, stripping the tool-call chain in between); when there are many turns, the earlier half is trimmed and summarized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overflow fallback&lt;/strong&gt;: if the model API itself throws a context-overflow error, the system first summarizes the current conversation into memory, then applies a more aggressive truncation. This is the last line of defense.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fej0ucdr4xpv3ivvlxziy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fej0ucdr4xpv3ivvlxziy.png" alt="The four-step flow of smart context compression" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Post-Session Review
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Post-session review&lt;/strong&gt; is the most active and most central part of self-evolution. When a session wraps up and goes idle, the Agent revisits the whole conversation: fixing problems that surfaced, turning reusable workflows into skills, finishing tasks that were left undone.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 What It Improves
&lt;/h3&gt;

&lt;p&gt;Here is what a review mainly does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Improve and create skills&lt;/strong&gt;: when a Skill exposed a problem in use (wrong configuration, a missing step, stale content), the Agent edits the skill file directly so it does not recur; when a reusable workflow emerged in the conversation, the Agent turns it into a new skill so the next similar task runs more reliably. This step turns the Agent from a &lt;em&gt;user&lt;/em&gt; of skills into a &lt;em&gt;maintainer&lt;/em&gt; of skills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finish unfinished tasks&lt;/strong&gt;: tasks promised to the user but left undone, or interrupted by a transient failure (a network hiccup, an environment issue), get reviewed and attempted again.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fill gaps in memory / knowledge / prompts&lt;/strong&gt;: only as a backstop. The main conversation already writes memory and knowledge on its own, so this is a fallback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmo9xucf6ao3jvhqoi0p3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmo9xucf6ao3jvhqoi0p3.png" alt="Example of post-session review in action" width="799" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Example above: during a post-session review the Agent spots a reusable workflow, turns it into a new skill, and notifies the user.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two design trade-offs run through this layer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Skills and unfinished tasks are the primary value; memory, knowledge, and prompts are only gap-filling, since they are already covered by the other layers and need no duplicate attention.&lt;/li&gt;
&lt;li&gt;Fix the source, do not just log the symptom. If the root cause lives in a skill, the right move is to edit that skill, not to leave a note in memory saying "skill X has a bug." Many Agent projects stop at the symptom. Recording a symptom does not prevent recurrence; only fixing the source does.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3.2 When It Triggers
&lt;/h3&gt;

&lt;p&gt;Review fires after a session ends and stays idle for a while, and only once enough conversation has accumulated to be worth reviewing. In short: the user has stopped chatting, and the session held enough substance. Both conditions must hold before a single review runs.&lt;/p&gt;

&lt;p&gt;In the project, self-evolution can be toggled on or off from the Web console, and the idle threshold (10 minutes by default) and turn threshold (6 turns by default) can be tuned further in the config file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5l37ypfyw7j3u9y3iuk9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5l37ypfyw7j3u9y3iuk9.png" alt="The self-evolution toggle and configuration in the Web console" width="799" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3 Safety and Control
&lt;/h3&gt;

&lt;p&gt;Once you let an Agent edit itself, the question that matters most is whether it might break something or interrupt the user. A system that can modify itself tends to fail in a few specific ways: writing wrong information into memory or skills; overstepping its scope and touching built-in modules while running commands; or making changes that cannot be traced or rolled back.&lt;/p&gt;

&lt;p&gt;So this layer is designed around three goals: &lt;strong&gt;traceable, reversible, isolated execution&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Isolated execution&lt;/strong&gt;: each review is a separate, asynchronous, temporary task. It uses the same main model but with a sharply narrowed tool set (it can only read context and edit memory and skills), so it neither pollutes nor slows the main conversation. The project's own built-in skills are write-protected at the code level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reversible changes&lt;/strong&gt;: relevant files are backed up automatically before the Agent edits them. If a user disagrees with a change, sending a message like "undo the last change" restores the workspace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traceable changes&lt;/strong&gt;: every change is persisted in the workspace, and the details can be tracked under "Web console → Memory → Self-Evolution."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No change, no interruption&lt;/strong&gt;: after a review, the Agent checks whether anything was actually changed. If so, it pushes the result to the user; if not, it stays silent and the user notices nothing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93dypzfnh1ka30z3b2ur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93dypzfnh1ka30z3b2ur.png" alt="The self-evolution record list under memory management" width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Dream-Based Memory Consolidation
&lt;/h2&gt;

&lt;p&gt;Dream-based memory consolidation (Deep Dream) runs as a nightly scheduled task (23:55 by default). It first writes each session's context (short-term memory) for the day into daily memory, then runs a distillation pass: it reads the current core memory and the day's daily memory and asks the model to deduplicate, merge near-duplicate entries, prune, extract new information, and replace stale entries, producing a refined core memory. It also writes a narrative dream journal recording what this pass found, merged, and cleaned up.&lt;/p&gt;

&lt;p&gt;This is a daily, global-scope form of self-evolution, a single sweep over all of the day's sessions. It addresses the two problems long-term memory runs into over time: &lt;strong&gt;unbounded growth&lt;/strong&gt; and &lt;strong&gt;internal contradiction&lt;/strong&gt;. The pass follows a few core rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple near-identical entries are merged into one higher-density statement.&lt;/li&gt;
&lt;li&gt;New information worth keeping (preferences, decisions, rules, lessons) is extracted from the daily journals; when new and old memory conflict, the new entry replaces the old one.&lt;/li&gt;
&lt;li&gt;Temporary records, empty entries, and redundancy already covered elsewhere are cleaned out, keeping core memory (&lt;code&gt;MEMORY.md&lt;/code&gt;) within a bounded size (around 50 entries).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7sxup7f8mmuu2ddderza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7sxup7f8mmuu2ddderza.png" alt="Example of a dream journal produced by memory consolidation" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few safeguards keep consolidation safe and controlled:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there are no new journals for the day, the pass is skipped, so it never overwrites existing core memory with nothing.&lt;/li&gt;
&lt;li&gt;Journal content and each message are hashed for deduplication, so the same content is never written into daily memory twice (even across days).&lt;/li&gt;
&lt;li&gt;The prompt strongly constrains the pass to the actual records, so it does not invent memories that never existed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Besides the nightly run, consolidation can be triggered manually for the last N days. All consolidation output is persisted in the workspace as journals.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Source-Code Self-Update
&lt;/h2&gt;

&lt;p&gt;Source-code self-update means the Agent modifies its own code at runtime and restarts, to solve problems that external skills and tools cannot. Because this carries some risk, the discussion here is more open-ended.&lt;/p&gt;

&lt;p&gt;For safety, the project does not ship source-code self-update as a built-in, enabled feature. Users can still achieve it by asking for it directly. The project installs from source by default, so the Agent already has access to its own code; you only need to tell it where the project code lives and give a clear change request, and it can modify its own code and restart. To make it more proactive about editing code, you can wrap this into a Skill or prompt as a built-in capability.&lt;/p&gt;

&lt;p&gt;Editing code changes the Agent's capabilities themselves, not just data like memory or skills, so the blast radius is larger. Two hard problems stand out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to keep the Agent from breaking the code and failing to start.&lt;/li&gt;
&lt;li&gt;How to shut down the current process and start a new one from within the running process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To handle both, the project provides a &lt;code&gt;cow self-restart&lt;/code&gt; CLI command dedicated to the Agent restarting itself. It first runs a self-check on the code; any import or interpreter error aborts the restart. Once the check passes, it launches a relay process detached from the current process tree, which shuts down the old process and starts a new one, achieving a graceful self-restart.&lt;/p&gt;

&lt;p&gt;In an open-source setting there is one more issue: version conflicts. Once the code is modified locally, it diverges from the upstream branch, and a later official update may conflict on pull. Resolving that still relies on a person, or on the Agent's help.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhf2icx9vv3svbhgk9q59.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhf2icx9vv3svbhgk9q59.png" alt="Example of the Agent editing its own code and restarting" width="799" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Example above: the Agent locates a problem in its own code and fixes it, then runs the command to self-check and restart.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Across these five layers, the Agent learns to adjust its own prompts, memory, knowledge, skills, and even its source code. Looking back at the design, the hard part was never giving it the ability to change itself; it was making those changes restrained and controllable. The goal is plain: an Agent that understands you better and makes fewer mistakes the more you use it, instead of one that meets you fresh every day.&lt;/p&gt;

&lt;p&gt;The implementation here comes from the open-source project CowAgent. If the ideas are useful, the &lt;a href="https://github.com/zhayujie/CowAgent" rel="noopener noreferrer"&gt;source&lt;/a&gt; and &lt;a href="https://docs.cowagent.ai/memory/self-evolution" rel="noopener noreferrer"&gt;docs&lt;/a&gt; are there to look at.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>llm</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
