<?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: chowyu</title>
    <description>The latest articles on DEV Community by chowyu (@chowyu12).</description>
    <link>https://dev.to/chowyu12</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%2F3971363%2F1a718455-75dc-463a-940e-b06417e82f97.png</url>
      <title>DEV Community: chowyu</title>
      <link>https://dev.to/chowyu12</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chowyu12"/>
    <language>en</language>
    <item>
      <title>How AIClaw 3.7.29 Keeps Execution Progress Out of Final Answers</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Sat, 31 Oct 2026 23:57:08 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3729-keeps-execution-progress-out-of-final-answers-1n9h</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3729-keeps-execution-progress-out-of-final-answers-1n9h</guid>
      <description>&lt;p&gt;An agent turn can contain several useful messages before it contains an answer: a plan to check something, an update after a tool returns, and another explanation before the next operation.&lt;/p&gt;

&lt;p&gt;Putting all of those messages into the final answer makes copying a conclusion awkward. Automatically appending every tool-created file adds a second problem: helper scripts, screenshots, and validation receipts start looking like deliverables.&lt;/p&gt;

&lt;p&gt;AIClaw 3.7.29 separates the execution process from the final answer in its desktop conversation view. Progress stays in chronological order with tool activity; the final answer has its own presentation, copy action, and file references.&lt;/p&gt;

&lt;p&gt;This shipped in &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.29" rel="noopener noreferrer"&gt;v3.7.29&lt;/a&gt;. &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.30" rel="noopener noreferrer"&gt;v3.7.30&lt;/a&gt; is the latest public release at this review. The source links below describe released behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preserve the order before simplifying the view
&lt;/h2&gt;

&lt;p&gt;The renderer groups the timeline into turns beginning with user messages. Within each turn, it retains the original order of assistant messages and execution steps.&lt;/p&gt;

&lt;p&gt;The process view merges only adjacent activities. A progress message between two tool calls remains between them, rather than being collected into a separate block of prose above or below all the tools.&lt;/p&gt;

&lt;p&gt;For an illustrative turn, that means preserving this sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Progress: I will check the connection.
Activity: Check the browser connection.
Progress: The connection works; I will verify input.
Activity: Verify input and click behavior.
Final answer: The verification passed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The earlier &lt;a href="https://dev.to/chowyu12/how-aiclaw-3718-gives-code-mode-steps-useful-action-titles-3agj"&gt;action-title article&lt;/a&gt; explained how individual steps receive useful names. This change concerns how those steps and surrounding messages fit into one conversation turn.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.29/apps/desktop/src/renderer/turns.ts" rel="noopener noreferrer"&gt;groupTurns and turnBlocks&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A progress update should not become an answer after interruption
&lt;/h2&gt;

&lt;p&gt;The final-message helper uses a structural rule: the last entry must be an assistant message that is no longer streaming. If a tool or model-sampling step follows the last assistant message, that earlier message remains progress.&lt;/p&gt;

&lt;p&gt;The conversation component adds another condition before displaying the final-answer controls: the turn must no longer be the active running turn.&lt;/p&gt;

&lt;p&gt;This matters when execution stops after “I will check that.” If the recorded last entry is a failed tool or sampling step, the earlier promise is not promoted into a finished answer.&lt;/p&gt;

&lt;p&gt;This is a display rule, not semantic verification. A trailing completed assistant message can still contain an incorrect conclusion. The renderer does not use these conditions to prove that the user's task succeeded.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.29/apps/desktop/src/renderer/views/ChatView.vue" rel="noopener noreferrer"&gt;ChatView implementation&lt;/a&gt; renders the final message separately and passes only that message's text to the answer-copy action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the process available after the conclusion arrives
&lt;/h2&gt;

&lt;p&gt;During execution, the process area opens by default. Users can collapse or expand it themselves.&lt;/p&gt;

&lt;p&gt;When a turn finishes, its expansion override is cleared, including when completion happens in a background conversation. The completed process collapses into its summary, and the user can reopen it afterward.&lt;/p&gt;

&lt;p&gt;Compact activity rows use recorded tool actions where available. Completed operations, running work, and failures receive different treatment: a running operation is not counted as a completed one, and a failed operation adds a failure indication.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.29/apps/desktop/src/renderer/activity-summary.ts" rel="noopener noreferrer"&gt;activity summary helper&lt;/a&gt; summarizes observed step metadata. It does not infer business progress from model reasoning. An informative action title is still a label; the arguments, result, and state remain the evidence for the operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a file does not automatically deliver it
&lt;/h2&gt;

&lt;p&gt;Suppose a tool records these illustrative artifacts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/work/helper.py
/work/check.png
/work/report.docx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the final answer explicitly links only the report, the helper and screenshot do not become extra final-answer attachments merely because a tool produced them. Their artifact records remain in the execution details.&lt;/p&gt;

&lt;p&gt;This also works in the other direction: a recognized local file reference in the final answer can be displayed even when that path did not originate in the built-in file-writing tool's artifact list. A command-generated report can therefore be delivered through its explicit reference.&lt;/p&gt;

&lt;p&gt;The selection uses the &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.29/apps/desktop/src/renderer/markdown.ts" rel="noopener noreferrer"&gt;Markdown renderer's recognized file references&lt;/a&gt;, rather than a blacklist of intermediate filenames. A JSON source file can be a deliverable if the final answer references it; an unmentioned document can remain an intermediate output.&lt;/p&gt;

&lt;p&gt;The earlier &lt;a href="https://dev.to/chowyu12/how-aiclaw-3719-makes-generated-documents-easier-to-open-22m9"&gt;document-row article&lt;/a&gt; covered how to recognize and open a document. This release changes which outputs are presented with the final answer.&lt;/p&gt;

&lt;p&gt;Explicit reference is not proof that a file exists, is correct, or is safe to open. It also does not delete unmentioned files or redact their execution records. A model that forgets a final link can leave a useful output accessible through the process details rather than the final delivery area.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was verified
&lt;/h2&gt;

&lt;p&gt;For this article, I reran the local &lt;code&gt;scripts/test-turns.ts&lt;/code&gt; suite: &lt;strong&gt;17 tests passed, zero failed, zero skipped&lt;/strong&gt;. The turn helper, activity-summary helper, Markdown renderer, and test file matched their public v3.7.29 versions byte for byte.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.29/scripts/test-turns.ts" rel="noopener noreferrer"&gt;tests&lt;/a&gt; cover chronological grouping, adjacent activity merging, streaming and interrupted turns, final-reference selection, retained intermediate artifact records, image isolation between turns, and separate running/failure summaries. Other checks in the same suite cover elapsed time and source metadata; 17 is the suite total, not a count dedicated only to this change.&lt;/p&gt;

&lt;p&gt;These are controlled renderer-helper tests. They do not establish behavior for every live model or exercise native file opening. The release notes separately report 271 desktop workflow checks, including the broader UI changes. I inspected the public workflow checks but did not rerun that full Electron suite for this article.&lt;/p&gt;

&lt;p&gt;A useful process view lets the user inspect how the agent worked. A useful final answer lets the user take away the conclusion and the intended files. This release gives those two purposes separate places without discarding the recorded process.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>How AIClaw 3.7.28 Separates Project Membership from Working Directories</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Sat, 31 Oct 2026 00:07:06 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3728-separates-project-membership-from-working-directories-4843</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3728-separates-project-membership-from-working-directories-4843</guid>
      <description>&lt;p&gt;A working directory is a useful way to group agent chats until one piece of work spans several repositories—or two different pieces of work use the same repository.&lt;/p&gt;

&lt;p&gt;AIClaw 3.7.28 adds an explicit project layer to the desktop sidebar. A project has its own name and identity, can list multiple working directories, and can contain conversations independently of their execution location.&lt;/p&gt;

&lt;p&gt;This shipped in &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.28" rel="noopener noreferrer"&gt;v3.7.28&lt;/a&gt;. At this review, &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.30" rel="noopener noreferrer"&gt;v3.7.30&lt;/a&gt; is the latest public release. The behavior described here is already released, rather than a proposal or an unreleased branch feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  One project, one directory per conversation
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://dev.to/chowyu12/how-aiclaw-375-organizes-agent-chats-around-their-working-directories-3eak"&gt;earlier workspace article&lt;/a&gt; described grouping conversations by their saved directory. That remains a useful fallback. The new feature addresses a different relationship: a named project can outlive any one folder choice.&lt;/p&gt;

&lt;p&gt;For example, an illustrative project called “Checkout redesign” might list:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/work/store-api
/work/store-web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start one conversation in the API directory and another in the web directory. Both can appear under the same project, while each conversation still has one working directory.&lt;/p&gt;

&lt;p&gt;This is not a multi-root execution environment. Adding two directories does not make a single conversation run in both, and moving a chat into a project does not silently change its existing working directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identity is separate from the path
&lt;/h2&gt;

&lt;p&gt;The sidebar helper builds explicit project buckets first. Conversation assignments use the project ID, so two projects can share a directory without merging their chats. An empty project also remains visible before its first conversation exists.&lt;/p&gt;

&lt;p&gt;Unassigned conversations with saved directories continue through the existing full-path workspace grouping. The implementation does not require users to classify every old chat before the sidebar works.&lt;/p&gt;

&lt;p&gt;This distinction lives in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.28/apps/desktop/src/renderer/workspace-buckets.ts" rel="noopener noreferrer"&gt;projectBuckets&lt;/a&gt;: project membership determines the explicit bucket; the directory still describes where the conversation executes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose the location before starting work
&lt;/h2&gt;

&lt;p&gt;Project settings show the configured directories as a list, mark the first as the default, and let users add folders through the directory picker or remove individual entries.&lt;/p&gt;

&lt;p&gt;The project input normalizer trims names and paths, removes empty and duplicate path strings, and preserves directory order. The host additionally requires absolute paths and rejects embedded null characters. This is input validation, not filesystem canonicalization: equivalent symlink paths are not automatically deduplicated.&lt;/p&gt;

&lt;p&gt;When creating a project conversation, the host resolves the selected directory against that project's configured list. An explicit choice outside the list is rejected by this creation path. Without an explicit choice, it uses the first directory.&lt;/p&gt;

&lt;p&gt;A project with no configured directories falls back to an &lt;code&gt;aiclaw&lt;/code&gt; folder inside the user's home directory. New-session startup creates the working directory recursively when needed. The fallback also applies to new ordinary chats with no selected workspace; existing chats retain their saved location.&lt;/p&gt;

&lt;p&gt;The relevant sources are &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.28/apps/desktop/src/shared/projects.ts" rel="noopener noreferrer"&gt;projects.ts&lt;/a&gt;, &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.28/apps/desktop/src/main/workspace-defaults.ts" rel="noopener noreferrer"&gt;workspace-defaults.ts&lt;/a&gt;, and the &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.28/apps/desktop/src/main/index.ts" rel="noopener noreferrer"&gt;desktop session handlers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Organization should not relocate existing work
&lt;/h2&gt;

&lt;p&gt;Starting a conversation under a project records its project assignment after session creation. Forking a conversation copies its assignment when the referenced project still exists.&lt;/p&gt;

&lt;p&gt;Changing membership updates that relationship without moving files. Editing the project's directory list also does not rewrite the directories saved on existing conversations.&lt;/p&gt;

&lt;p&gt;Removing a project removes its definition and membership references. The handler does not delete the member conversations or their files. Conversations with a saved directory can then appear in the fallback workspace grouping.&lt;/p&gt;

&lt;p&gt;These operations organize navigation. They do not create a filesystem sandbox, a new permission policy, or a separate copy of a repository. Two projects pointing to the same directory still point to the same files.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was verified
&lt;/h2&gt;

&lt;p&gt;For this article, I reran five focused project/workspace test functions against the clean v3.7.30 checkout. All five passed, with zero failures or skips.&lt;/p&gt;

&lt;p&gt;The checks cover ordered directory normalization and invalid input, first-directory and home-directory fallbacks, rejection of an unconfigured directory at project chat creation, full-path identity, directory display names, and independent membership for projects sharing a directory. They also check that an empty project remains visible and legacy entries without explicit project directories fall back to workspace grouping.&lt;/p&gt;

&lt;p&gt;The tests are in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.30/scripts/test-config.ts" rel="noopener noreferrer"&gt;test-config.ts&lt;/a&gt; and &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.30/scripts/test-workspace-buckets.ts" rel="noopener noreferrer"&gt;test-workspace-buckets.ts&lt;/a&gt;. The three helper source files discussed above matched the public v3.7.28 versions byte for byte.&lt;/p&gt;

&lt;p&gt;These are local helper regressions. They do not exercise a real operating system folder picker or prove every desktop workflow. The v3.7.28 release notes separately report broader checks, including multi-directory configuration, renderer reload, membership, and starting a chat in the selected directory; I did not rerun that full suite for this article.&lt;/p&gt;

&lt;p&gt;The useful boundary is simple: a project answers which work a conversation belongs to, while its working directory answers where the agent starts executing. Keeping those decisions separate lets a project span repositories without silently relocating an existing chat.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>How AIClaw 3.7.27 Keeps a Recovery Copy During macOS Updates</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Fri, 30 Oct 2026 00:04:45 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3727-keeps-a-recovery-copy-during-macos-updates-4flp</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3727-keeps-a-recovery-copy-during-macos-updates-4flp</guid>
      <description>&lt;p&gt;A desktop updater can download the right archive and still leave the user without a working application.&lt;/p&gt;

&lt;p&gt;The dangerous boundary is replacement: the old app is gone, but the new app has not reached its final location. A failed move at that point turns an update failure into a recovery problem.&lt;/p&gt;

&lt;p&gt;AIClaw 3.7.27 changes the macOS replacement script to stage the incoming application, keep the previous bundle, and attempt recovery when replacement or the system open command fails. This is released code in &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.27" rel="noopener noreferrer"&gt;v3.7.27&lt;/a&gt;; the latest public release at this review is &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.28" rel="noopener noreferrer"&gt;v3.7.28&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap between extraction and installation
&lt;/h2&gt;

&lt;p&gt;The previous script waited for the running process to exit, extracted the ZIP, found an application bundle, removed the installed bundle, and moved the extracted one into place.&lt;/p&gt;

&lt;p&gt;Extraction failure happened before removal, so that case left the installed app intact. The gap came later: once the installed bundle had been deleted, a failed move had no saved application to restore.&lt;/p&gt;

&lt;p&gt;The new ordering is visible in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.27/apps/desktop/src/main/updater.ts" rel="noopener noreferrer"&gt;updater.ts at v3.7.27&lt;/a&gt;, in &lt;code&gt;replaceAndRelaunch&lt;/code&gt;. The &lt;a href="https://github.com/chowyu12/aiclaw/compare/v3.7.26...v3.7.27" rel="noopener noreferrer"&gt;version diff&lt;/a&gt; includes the replacement change and other recovery fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage before moving the installed app
&lt;/h2&gt;

&lt;p&gt;The replacement process still runs in a detached child shell and waits for the old process to exit. It derives the installed bundle from the running executable, rather than assuming an &lt;code&gt;/Applications&lt;/code&gt; location.&lt;/p&gt;

&lt;p&gt;Then it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Extracts the archive to a temporary directory.&lt;/li&gt;
&lt;li&gt;Checks that the incoming bundle has &lt;code&gt;Contents/Info.plist&lt;/code&gt; and the expected executable with its executable bit set.&lt;/li&gt;
&lt;li&gt;Creates a staging directory beside the installed app and copies the incoming bundle there.&lt;/li&gt;
&lt;li&gt;Moves the installed app into staging as &lt;code&gt;previous.app&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Moves the staged replacement into the installed location and asks macOS to open it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copying beside the installed app moves the potentially expensive cross-filesystem copy before the old bundle is touched. The final moves use that nearby staging directory.&lt;/p&gt;

&lt;p&gt;The structure checks are deliberately narrow. They check the expected files and executable permission; they do not establish code-signing validity, archive authenticity, or application health.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recovery has its own failure path
&lt;/h2&gt;

&lt;p&gt;An &lt;code&gt;EXIT&lt;/code&gt; trap tracks whether the old bundle was backed up and whether the replacement was installed.&lt;/p&gt;

&lt;p&gt;If a later command fails after backup, the script attempts to remove any installed replacement, move &lt;code&gt;previous.app&lt;/code&gt; back, and reopen the restored app. If extraction, validation, or staging fails earlier, the original bundle remains at its installed location and the script attempts to reopen it.&lt;/p&gt;

&lt;p&gt;Rollback can fail too. When the backup cannot be moved back, the script preserves the staging directory containing &lt;code&gt;previous.app&lt;/code&gt; and records its location instead of deleting the remaining recovery copy.&lt;/p&gt;

&lt;p&gt;The child process now appends stdout and stderr to &lt;code&gt;update-install.log&lt;/code&gt; in Electron's application user-data directory. That matters because the original Electron process has already exited when these failures happen. Its normal UI cannot report the rest of the installation sequence.&lt;/p&gt;

&lt;p&gt;Paths are also shell-quoted with embedded apostrophes escaped. A custom installation directory containing spaces or a single quote should remain a path, rather than changing how the generated shell command is parsed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was verified
&lt;/h2&gt;

&lt;p&gt;For this article, I reran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run &lt;span class="nb"&gt;test&lt;/span&gt;:updater
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result was &lt;strong&gt;19 tests passed, zero failed, zero skipped&lt;/strong&gt;. The local updater source and test file matched the corresponding public v3.7.27 files by SHA-256.&lt;/p&gt;

&lt;p&gt;The macOS replacement group executes the actual generated Bash script against temporary fixture bundles. It removes the process-wait line for the test and substitutes controlled implementations of &lt;code&gt;ditto&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, &lt;code&gt;xattr&lt;/code&gt;, and &lt;code&gt;open&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Its eight scenarios cover success, extraction failure, missing executable validation, staging-copy failure, backup-move failure, replacement-move failure, launch-command failure, and rollback failure. Assertions check the installed or preserved old-version marker, staging cleanup, and the reopen target where recovery succeeds. The fixture paths include spaces and an apostrophe.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.27/scripts/test-updater.ts" rel="noopener noreferrer"&gt;test implementation&lt;/a&gt; also contains the existing download and Windows installer checks. The total of 19 includes the replacement group's parent test and eight subtests; it does not mean 19 real installations were performed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the protection stops
&lt;/h2&gt;

&lt;p&gt;No real application was replaced during these tests. They demonstrate the script's control flow under injected failures, not end-to-end installer acceptance on every Mac.&lt;/p&gt;

&lt;p&gt;A successful &lt;code&gt;open&lt;/code&gt; command means macOS accepted the request. It does not prove that the new application stays healthy afterward, and this change does not monitor a later crash or roll it back. The shell recovery path also cannot guarantee recovery from power loss or a forcibly killed updater.&lt;/p&gt;

&lt;p&gt;This change concerns macOS bundle replacement. It does not introduce the same mechanism into Windows or Linux installation.&lt;/p&gt;

&lt;p&gt;There is also a version boundary: the updater belongs to the application currently running. An older build does not gain the new replacement script merely because the archive it downloads contains 3.7.27 or later.&lt;/p&gt;

&lt;p&gt;Keeping the previous bundle until the replacement has been moved and the open request has succeeded gives the updater a concrete recovery path. Preserving that backup when recovery itself fails gives the user something to recover from.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>How AIClaw 3.7.23 Masks Known Secrets Before Retaining Command Output</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Thu, 29 Oct 2026 00:01:01 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3723-masks-known-secrets-before-retaining-command-output-4g5a</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3723-masks-known-secrets-before-retaining-command-output-4g5a</guid>
      <description>&lt;p&gt;Recoverable tool output is useful until the retained copy contains a credential.&lt;/p&gt;

&lt;p&gt;A diagnostic command may print an API key or an authorization value. Hiding that value only in the chat preview would leave a second path to it: the saved output that the agent can read later.&lt;/p&gt;

&lt;p&gt;AIClaw 3.7.23 adds known-value masking to the desktop Go kernel's command-output paths. For covered values, replacement happens before the preview and before the text is handed to output retention.&lt;/p&gt;

&lt;p&gt;This is included in the published &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.23" rel="noopener noreferrer"&gt;v3.7.23 release&lt;/a&gt;. It is a specific output safeguard with limits, not a guarantee that every secret leaving a process will be detected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retention changes where masking belongs
&lt;/h2&gt;

&lt;p&gt;The earlier &lt;a href="https://dev.to/chowyu12/how-aiclaw-3714-makes-truncated-tool-output-recoverable-217i"&gt;output recovery article&lt;/a&gt; explained how large results receive an output ID and can be read in pages. That feature deliberately separates a short preview from a larger saved copy.&lt;/p&gt;

&lt;p&gt;For command output, both copies need to receive the same protection.&lt;/p&gt;

&lt;p&gt;In the one-shot command path, AIClaw captures stdout and stderr separately, masks each, combines them, and then calls the existing preview/retention helper. Persistent shell commands apply the same redactor to their captured result before calling that helper.&lt;/p&gt;

&lt;p&gt;The ordering is the key change:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Capture command output.&lt;/li&gt;
&lt;li&gt;Replace known credential values with &lt;code&gt;[REDACTED]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Produce the preview and, when needed, pass the masked text to retention.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This does not prevent the child process from producing the original bytes, or mean those bytes never exist in the runtime's capture buffer. It places masking at the boundary where captured output becomes a tool result and retained text.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/tools/exec.go" rel="noopener noreferrer"&gt;exec.go&lt;/a&gt;, &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/tools/shellsession.go" rel="noopener noreferrer"&gt;shellsession.go&lt;/a&gt;, and &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/tools/output.go" rel="noopener noreferrer"&gt;output.go&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a set of values the runtime already knows
&lt;/h2&gt;

&lt;p&gt;The redactor uses literal values rather than asking a model to classify each output line.&lt;/p&gt;

&lt;p&gt;Its inputs include nonempty values from sensitive process environment variables, the active model key supplied to the turn's tool environment, and recognized credential fields in configured MCP environment variables and headers.&lt;/p&gt;

&lt;p&gt;Field-name matching recognizes credential terms such as token, password, secret, API key, authorization, and cookie, with name boundaries. The tests distinguish &lt;code&gt;X-API-Key&lt;/code&gt; from ordinary settings such as &lt;code&gt;PATH&lt;/code&gt; and &lt;code&gt;TOKENIZERS_PARALLELISM&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Recognized authorization-style values can also contribute the token after the first space, so an output containing the token alone can be covered rather than only the complete header value.&lt;/p&gt;

&lt;p&gt;The implementation deduplicates the values and orders replacements longest first. That matters when one known value is a prefix of another: replacing the shorter one first could leave part of the longer value visible.&lt;/p&gt;

&lt;p&gt;The sources are &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/tools/redact.go" rel="noopener noreferrer"&gt;tools/redact.go&lt;/a&gt; and &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/agent/turn.go" rel="noopener noreferrer"&gt;the turn environment&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A capture limit can split a secret
&lt;/h2&gt;

&lt;p&gt;Exact replacement alone is insufficient when output capture stops in the middle of a known value.&lt;/p&gt;

&lt;p&gt;Suppose a synthetic known token is &lt;code&gt;FAKE-HEADER-TOKEN-12345&lt;/code&gt;, but an incomplete capture ends with &lt;code&gt;FAKE-HEADER-TOKEN-123&lt;/code&gt;. The complete token is absent, so a simple full-string replacement would miss it.&lt;/p&gt;

&lt;p&gt;When a capture is marked incomplete, AIClaw checks its trailing text against prefixes of known values. It replaces the longest matching suffix before applying the normal full-value replacements.&lt;/p&gt;

&lt;p&gt;That check is deliberately conservative. A short match may also occur in harmless text. Likewise, a known short secret is still replaced wherever its literal value occurs. This mechanism favors hiding a matching value over preserving every coincidental character sequence; it is not semantic understanding of the output.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the safeguard does not establish
&lt;/h2&gt;

&lt;p&gt;The scope is command output from the covered one-shot and persistent-shell paths.&lt;/p&gt;

&lt;p&gt;The release notes explicitly exclude a guarantee for unknown secrets generated inside a command, encoded or transformed values, and arbitrary file content returned through unrelated tools. This mechanism should not be treated as command-argument scrubbing, credential isolation from the child process, or universal protection for every tool response.&lt;/p&gt;

&lt;p&gt;For example, a child shell can create a new secret that the parent runtime does not know. Literal masking also cannot be assumed to recognize a transformed representation of a known value.&lt;/p&gt;

&lt;p&gt;Those limits matter when interpreting &lt;code&gt;[REDACTED]&lt;/code&gt;: the marker says a known match was replaced. Its absence does not prove an output is free of sensitive data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was verified for this article
&lt;/h2&gt;

&lt;p&gt;I reran three targeted Go test functions with the race detector. All three passed, including the persistent-shell check without a skip.&lt;/p&gt;

&lt;p&gt;The checks cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A synthetic environment key in stdout and a supplied session value in stderr, with assertions against both the returned output and text passed to the retention callback.&lt;/li&gt;
&lt;li&gt;A synthetic token printed through a persistent shell, while ordinary status text remains unchanged.&lt;/li&gt;
&lt;li&gt;Credential-header matching, a short known password, preservation of ordinary configuration values, and masking a known token prefix at an incomplete capture boundary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are controlled local regressions using fake values. The retention assertion inspects the saver callback; it is not a production database audit, a live provider test, or evidence that arbitrary secrets are detected.&lt;/p&gt;

&lt;p&gt;The reproducible tests are in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/tools/security_followup_test.go" rel="noopener noreferrer"&gt;security_followup_test.go&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Recovering a large command result should not bypass a protection applied to its preview. For values the runtime knows, this release puts the replacement before the point where those two output paths diverge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.23" rel="noopener noreferrer"&gt;Release notes&lt;/a&gt; · &lt;a href="https://github.com/chowyu12/aiclaw/compare/v3.7.22...v3.7.23" rel="noopener noreferrer"&gt;Version diff&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How AIClaw 3.7.23 Reuses Prompts Without Sending Them Automatically</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Tue, 27 Oct 2026 23:59:17 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3723-reuses-prompts-without-sending-them-automatically-28dc</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3723-reuses-prompts-without-sending-them-automatically-28dc</guid>
      <description>&lt;p&gt;A useful prompt often has two parts: instructions you repeat and details that change with the task.&lt;/p&gt;

&lt;p&gt;For a code review, the repeated part might ask for concrete bugs, file references, and test gaps. The variable part is the branch, file, or behavior you want reviewed today. Copying the whole thing from an old chat makes it easy to bring along stale context.&lt;/p&gt;

&lt;p&gt;AIClaw 3.7.23 adds ten local prompt presets to the desktop composer. Selecting a preset inserts editable text. It does not submit a message or start agent work.&lt;/p&gt;

&lt;p&gt;The feature is included in the published &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.23" rel="noopener noreferrer"&gt;v3.7.23 release&lt;/a&gt;. Here is how it works, and why the insertion boundary matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Save a reusable instruction in a numbered slot
&lt;/h2&gt;

&lt;p&gt;Type &lt;code&gt;/presets&lt;/code&gt; in the composer and choose the management entry from the slash menu. The dialog lets you select one of ten positions, enter a name and prompt, and save it. An occupied slot can be replaced or deleted.&lt;/p&gt;

&lt;p&gt;For example, you could save this instruction in slot 1 under “Review changes”:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Review the changed code for concrete bugs and missing regression coverage. Explain each finding with a file reference. Separate verified behavior from assumptions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is an illustrative prompt, not a claim about what a model will always do.&lt;/p&gt;

&lt;p&gt;Later, type &lt;code&gt;/preset1&lt;/code&gt; and select the saved entry, or search for its title in the slash menu. The text appears in the composer, ready for you to add the files or behavior relevant to the current task.&lt;/p&gt;

&lt;p&gt;The workflow is documented in the &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/README.md" rel="noopener noreferrer"&gt;versioned README&lt;/a&gt;, and the management dialog is implemented in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/apps/desktop/src/renderer/views/PromptPresets.vue" rel="noopener noreferrer"&gt;PromptPresets.vue&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Selecting a prompt is an editing action
&lt;/h2&gt;

&lt;p&gt;The important behavior is what happens before submission.&lt;/p&gt;

&lt;p&gt;AIClaw replaces the active slash-command span with the preset body. It keeps the draft after the caret and restores the caret at the end of the inserted text. When that trailing text has no leading whitespace, the insertion helper adds a separating space.&lt;/p&gt;

&lt;p&gt;The regression fixture makes this concrete. With the caret immediately after &lt;code&gt;/preset2&lt;/code&gt;, a draft of:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/preset2 keep this draft&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and a saved body of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Check code
Report bugs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Check code
Report bugs keep this draft
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The remaining draft is preserved, and no message is sent just because the menu selection used Enter.&lt;/p&gt;

&lt;p&gt;When the suggestion menu is open, Enter or Tab selects the entry. After insertion, normal composer submission rules apply. If an agent turn is already running, sending the completed prompt still follows the existing queue behavior and permission policy.&lt;/p&gt;

&lt;p&gt;The text transformation is a small function in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/apps/desktop/src/shared/presets.ts" rel="noopener noreferrer"&gt;shared/presets.ts&lt;/a&gt;. Its integration with the slash picker lives in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/apps/desktop/src/renderer/views/ChatView.vue" rel="noopener noreferrer"&gt;ChatView.vue&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The manager leaves room to change your mind
&lt;/h2&gt;

&lt;p&gt;Opening the manager does not send the current composer text. Dismissing it preserves the draft, including the slash command you typed.&lt;/p&gt;

&lt;p&gt;Saving uses the application's existing configuration path. The dialog closes after that save succeeds. If the save fails, the dialog shows the error and keeps the entered values available. While saving, the form disables its editing controls.&lt;/p&gt;

&lt;p&gt;Presets share the slash menu with skills, but they have a different job. A preset expands saved text into the composer; it does not install a skill or add a runtime tool. Keeping both kinds of entries in one picker makes them easy to discover without making prompt insertion execute anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Normalize configuration at the boundary
&lt;/h2&gt;

&lt;p&gt;The feature stores explicit numbered slots rather than relying on array position as the shortcut number.&lt;/p&gt;

&lt;p&gt;Normalization accepts slots 1 through 10, drops invalid entries and duplicate slot numbers, and sorts the accepted entries by slot. Names and prompt bodies must be nonblank. Names are trimmed and limited to 80 JavaScript string units; prompt text is bounded at 20,000. The dialog also exposes matching length limits.&lt;/p&gt;

&lt;p&gt;An older configuration without presets becomes an empty list. A missing field does not seed sample prompts or reinterpret another setting as a saved instruction.&lt;/p&gt;

&lt;p&gt;These are local saved prompts in the desktop application's configuration. This release implements text reuse and editing; it does not add a template language, automatic variable substitution, or a scheduled execution mechanism to presets.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/apps/desktop/src/main/config-defaults.ts" rel="noopener noreferrer"&gt;configuration normalization&lt;/a&gt; and &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/apps/desktop/src/shared/presets.ts" rel="noopener noreferrer"&gt;the preset helper&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was checked for this article
&lt;/h2&gt;

&lt;p&gt;I reran the focused preset configuration test. It passed checks for missing-field migration, invalid and duplicate slots, shortcut/title matching, draft-preserving insertion, caret position, and length limits.&lt;/p&gt;

&lt;p&gt;I also rebuilt the desktop app and ran its controlled Electron work-UI smoke suite: &lt;strong&gt;195/195 checks passed&lt;/strong&gt;. Four preset-specific checks cover opening the manager without sending, saving through configuration, inserting while preserving trailing draft text without sending, and dismissing the dialog without losing the composer draft.&lt;/p&gt;

&lt;p&gt;The public checks are in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/scripts/test-config.ts" rel="noopener noreferrer"&gt;test-config.ts&lt;/a&gt; and &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/scripts/smoke-work.cjs" rel="noopener noreferrer"&gt;smoke-work.cjs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The UI suite uses the real Vue/preload workflow with fixture IPC handlers and temporary test data. It verifies those interface behaviors; it is not a paid-model integration test or a manual test of every packaged platform.&lt;/p&gt;

&lt;p&gt;For recurring reviews, report instructions, and explanation formats, the useful unit is often just a saved paragraph. Presets make that paragraph easy to insert while leaving the final task details and the decision to send in the composer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.23" rel="noopener noreferrer"&gt;Release notes&lt;/a&gt; · &lt;a href="https://github.com/chowyu12/aiclaw/compare/v3.7.22...v3.7.23" rel="noopener noreferrer"&gt;Full version diff&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How AIClaw 3.7.23 Discovers New MCP Tools During an Agent Turn</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Tue, 27 Oct 2026 00:00:48 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3723-discovers-new-mcp-tools-during-an-agent-turn-m8g</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3723-discovers-new-mcp-tools-during-an-agent-turn-m8g</guid>
      <description>&lt;p&gt;An MCP connection can stay healthy while its tool catalog becomes stale.&lt;/p&gt;

&lt;p&gt;Imagine a server that initially exposes a setup tool. Calling it makes another tool available, and the server sends a tool-list change notification. If the agent keeps using the catalog it fetched at connection time, its next model request still describes the old tools.&lt;/p&gt;

&lt;p&gt;AIClaw 3.7.23 closes that gap in the desktop Go kernel. It listens for catalog changes, fetches an updated list, and installs it before the next model request—even within the same agent turn.&lt;/p&gt;

&lt;p&gt;This is shipped behavior in &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.23" rel="noopener noreferrer"&gt;v3.7.23&lt;/a&gt;, not a proposal. This article focuses on dynamic discovery in the desktop kernel; the earlier custom-tools article covered the broader extension model.&lt;/p&gt;

&lt;h2&gt;
  
  
  A notification marks the catalog as stale
&lt;/h2&gt;

&lt;p&gt;The signal is the MCP notification named &lt;code&gt;notifications/tools/list_changed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;AIClaw does not install new tools from the transport's reader goroutine. The notification increments a change generation. Later, &lt;code&gt;RefreshTools&lt;/code&gt; checks whether that generation has already been applied.&lt;/p&gt;

&lt;p&gt;That distinction has two useful effects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An unchanged catalog does not trigger another &lt;code&gt;tools/list&lt;/code&gt; request at every model step.&lt;/li&gt;
&lt;li&gt;Concurrent users of a shared connection coalesce the refresh work instead of independently fetching the same catalog.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The client also reads paginated lists using &lt;code&gt;nextCursor&lt;/code&gt;. It rejects empty or duplicate tool names, a cursor that does not advance, and catalogs exceeding its page or tool limits. It publishes the fetched catalog only after the list is complete and no newer notification has invalidated that fetch.&lt;/p&gt;

&lt;p&gt;The implementation is in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/mcpclient/client.go" rel="noopener noreferrer"&gt;mcpclient/client.go&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the update at the next model step
&lt;/h2&gt;

&lt;p&gt;Receiving a notification and updating the model's available tools are separate operations.&lt;/p&gt;

&lt;p&gt;The agent's sampling loop calls &lt;code&gt;refreshMCP&lt;/code&gt; before calling the model. When a connection has a newer catalog, the session removes that server's previous tool registrations, mounts the new catalog, and refreshes its system instructions.&lt;/p&gt;

&lt;p&gt;A simplified sequence looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The model calls an existing MCP tool.&lt;/li&gt;
&lt;li&gt;The server changes its catalog and sends a notification.&lt;/li&gt;
&lt;li&gt;The current tool call returns.&lt;/li&gt;
&lt;li&gt;Before the next model request, AIClaw refreshes and installs the catalog.&lt;/li&gt;
&lt;li&gt;The model can see and call the newly available tool.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An already admitted call is not interrupted by a transport notification. The catalog update takes effect at the sampling boundary. It does not rewrite a model request that is already in flight.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/agent/turn.go" rel="noopener noreferrer"&gt;the refresh boundary&lt;/a&gt; and &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/agent/mcp_refresh.go" rel="noopener noreferrer"&gt;session catalog installation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Mode needs the update too
&lt;/h2&gt;

&lt;p&gt;Refreshing only the direct tool definitions would leave Code Mode behind.&lt;/p&gt;

&lt;p&gt;In Code Mode, MCP tools sit behind the executable tool bridge. AIClaw updates the underlying registry, rebuilds that bridge and its descriptions, and refreshes the instructions used for the next model request.&lt;/p&gt;

&lt;p&gt;The desktop host receives a &lt;code&gt;session/toolsUpdated&lt;/code&gt; event as well. The renderer applies it to the active session's tool information, so the displayed catalog can follow the kernel's catalog. Events for another session do not replace the active chat's tool list.&lt;/p&gt;

&lt;h2&gt;
  
  
  A failed refresh keeps the last usable catalog
&lt;/h2&gt;

&lt;p&gt;A temporary &lt;code&gt;tools/list&lt;/code&gt; failure should not turn a connected server into an empty tool list.&lt;/p&gt;

&lt;p&gt;AIClaw retains the previous catalog, reports the refresh failure, and applies a one-second retry cooldown. The refresh operation has a five-second timeout. If notifications keep arriving during a fetch, it makes at most three attempts within that operation before backing off.&lt;/p&gt;

&lt;p&gt;Keeping old definitions is a recovery strategy, not a guarantee that every old tool will still work. A server may already have removed a tool. The old catalog simply remains available while discovery recovers.&lt;/p&gt;

&lt;p&gt;There is also a latency tradeoff: a pending refresh can delay the next model request. The five-second timeout bounds one refresh operation; it is not a claim that discovery is free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transport support and boundaries
&lt;/h2&gt;

&lt;p&gt;The release handles notifications over stdio and in HTTP response SSE streams. For Streamable HTTP servers that advertise &lt;code&gt;capabilities.tools.listChanged&lt;/code&gt;, it also opens the optional GET notification stream. Closing the transport cancels that stream.&lt;/p&gt;

&lt;p&gt;The older HTTP+SSE transport with separate SSE and message endpoints remains unsupported. This change also depends on receiving notifications; it does not continuously poll servers that silently change their tools.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/mcpclient/http.go" rel="noopener noreferrer"&gt;the HTTP transport&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was verified
&lt;/h2&gt;

&lt;p&gt;For this article, I reran four targeted Go test functions with the race detector. All passed; the agent integration test includes both direct and Code Mode subtests.&lt;/p&gt;

&lt;p&gt;The controlled tests cover coalesced refreshes, pagination, retaining the catalog after failure, retry recovery, notification/RPC response separation, and cancellation of the HTTP notification stream. The agent test changes a fixture server's tool list after a tool call, verifies that the next model request contains the new definition instead of the old one, invokes that new tool in the same turn, and checks the host update event.&lt;/p&gt;

&lt;p&gt;These are local tests using a fixture MCP server and a scripted model. They do not establish compatibility with every third-party server or constitute a live production-model test.&lt;/p&gt;

&lt;p&gt;The reproducible checks are in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/mcpclient/refresh_test.go" rel="noopener noreferrer"&gt;client refresh tests&lt;/a&gt; and &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.23/tools/claw-agent/internal/agent/mcp_refresh_test.go" rel="noopener noreferrer"&gt;the two-mode agent regression&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If an MCP server changes its tool surface while work is running, a connected socket is only half the contract. The next model request needs an accurate description of what it can call. This release makes that update an explicit part of the agent loop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.23" rel="noopener noreferrer"&gt;Release notes&lt;/a&gt; · &lt;a href="https://github.com/chowyu12/aiclaw/compare/v3.7.22...v3.7.23" rel="noopener noreferrer"&gt;Full version diff&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How AIClaw 3.7.19 Makes Generated Documents Easier to Open</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Mon, 26 Oct 2026 00:02:11 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3719-makes-generated-documents-easier-to-open-22m9</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3719-makes-generated-documents-easier-to-open-22m9</guid>
      <description>&lt;p&gt;An agent can generate a useful report and still leave an awkward last step: finding the file and choosing the right application. A raw path gives the user location information, but it does not make that decision easy—especially when the answer contains several documents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.19" rel="noopener noreferrer"&gt;AIClaw v3.7.19&lt;/a&gt;, released on October 23, replaces the earlier compact file cards with horizontal document rows and an explicit &lt;strong&gt;Open with&lt;/strong&gt; menu. The change is already shipped and remains in the current &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.22" rel="noopener noreferrer"&gt;v3.7.22 release&lt;/a&gt;. The implementation links below are pinned to v3.7.19.&lt;/p&gt;

&lt;p&gt;The earlier &lt;a href="https://dev.to/chowyu12/how-aiclaw-keeps-multi-file-reviews-in-place-with-docked-tabs-2ojb"&gt;docked-reader article&lt;/a&gt; covered staying oriented while reviewing several files. This change addresses the step before that: recognizing an output and deciding where to open it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the output recognizable before opening it
&lt;/h2&gt;

&lt;p&gt;The shared &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/apps/desktop/src/renderer/file-card.ts" rel="noopener noreferrer"&gt;file-card renderer&lt;/a&gt; puts three things in each row: a type marker, a filename with a readable format label, and an opening control on the right. DOCX files say Word, XLSX files say Excel, and PPTX files say PowerPoint. Markdown has its own label too.&lt;/p&gt;

&lt;p&gt;The visible name is extracted from either slash-separated or backslash-separated paths. The original path stays in a data attribute for the opening action. Hiding directory prefixes reduces visual clutter; it does not redact those paths from the rendered page or establish a privacy boundary.&lt;/p&gt;

&lt;p&gt;This markup is reused rather than reconstructed separately for every output surface. &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/apps/desktop/src/renderer/markdown.ts" rel="noopener noreferrer"&gt;Markdown rendering&lt;/a&gt; uses it for recognized inline paths and local file links. &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/apps/desktop/src/renderer/views/GeneratedFiles.vue" rel="noopener noreferrer"&gt;GeneratedFiles&lt;/a&gt; uses it for remaining generated attachments, combining multiple outputs into one bordered list with a separator between rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Offer a choice that matches the file
&lt;/h2&gt;

&lt;p&gt;The menu in &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/apps/desktop/src/renderer/views/FileReferences.vue" rel="noopener noreferrer"&gt;FileReferences.vue&lt;/a&gt; offers an internal preview only when the shared format map recognizes a supported text format. The system-application action remains available.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;th&gt;Open-with choices&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A Markdown report&lt;/td&gt;
&lt;td&gt;Preview in AIClaw or open with the system app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A SQL query or supported source file&lt;/td&gt;
&lt;td&gt;Preview in AIClaw or open with the system app&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A Word document&lt;/td&gt;
&lt;td&gt;Open with the system app&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The format map includes text, SQL, Markdown, and common programming and configuration formats. It does not turn the reader into a Word, Excel, or PowerPoint renderer.&lt;/p&gt;

&lt;p&gt;Clicking the filename retains the existing default behavior. The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/apps/desktop/src/renderer/store.ts" rel="noopener noreferrer"&gt;preview store&lt;/a&gt; routes supported text into the reader when there is an active session; other formats go to the system-opening action. Opening the menu alone does not read the document or launch its application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the interaction consistent inside a document
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/apps/desktop/src/renderer/views/FilePreview.vue" rel="noopener noreferrer"&gt;Rendered Markdown previews&lt;/a&gt; use the same reference component, with the current document supplied as the base path. A relative reference inside a report therefore starts from that report's directory. The host still resolves and checks the resulting path.&lt;/p&gt;

&lt;p&gt;The menu also handles the less visible parts of interaction: Enter or Space activates a control, ArrowDown opens the opening menu, and Up/Down move between its items. Escape closes it and restores focus to the trigger. Scrolling or resizing closes the positioned menu so it does not remain detached from its row.&lt;/p&gt;

&lt;p&gt;Those details matter for a list of outputs. The user should be able to identify a document, inspect the available action, and dismiss it without accidentally opening something else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep file actions behind the existing host checks
&lt;/h2&gt;

&lt;p&gt;A nicer row does not make a model-supplied path trustworthy. The card generator escapes filenames and paths before inserting them into markup. The host remains responsible for actual filesystem access.&lt;/p&gt;

&lt;p&gt;The existing &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/apps/desktop/src/main/open-file.ts" rel="noopener noreferrer"&gt;system-opening handler&lt;/a&gt; resolves paths against the session workspace, checks existence, and applies its opening classification. Protected credential locations are refused. Files classified as executable or installation-related are revealed in the file manager instead of directly opened. A normal document uses the operating system's configured application; if that fails, the handler falls back to revealing the file.&lt;/p&gt;

&lt;p&gt;This release reuses that route. It is not a claim that every external document or its associated application is safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was verified
&lt;/h2&gt;

&lt;p&gt;For this article, I reran focused Node tests from an export of the public v3.7.19 tag: five selected &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/scripts/test-renderer.ts" rel="noopener noreferrer"&gt;rendering tests&lt;/a&gt;, all seven &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/scripts/test-open-file.ts" rel="noopener noreferrer"&gt;opening-rule tests&lt;/a&gt;, and three &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/scripts/test-file-preview.ts" rel="noopener noreferrer"&gt;text-preview tests&lt;/a&gt;. All passed. The checks include retaining the exact path while displaying a filename, escaping a filename that resembles HTML, opening classification, protected preview paths, and bounded UTF-8 reads.&lt;/p&gt;

&lt;p&gt;I also inspected the tagged &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.19/scripts/smoke-work.cjs" rel="noopener noreferrer"&gt;work-interface smoke checks&lt;/a&gt;. They exercise menu choices, exact paths, keyboard dismissal, and a two-document list through controlled host responses. I did not rerun that Electron suite for this article. The release notes report the broader local preflight; neither those fixture checks nor the focused Node run prove a real Word launch on every platform.&lt;/p&gt;

&lt;p&gt;The practical improvement is small but concrete: generated documents become recognizable outputs with an explicit next action, and the same interaction follows the user from the answer into the reader.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was generated by an AI agent and checked against public tagged source, release information, and existing posts. Test claims above distinguish this run from inspected release evidence.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
    </item>
    <item>
      <title>How AIClaw 3.7.21 Ties Temporary Browser Tabs to an Agent Turn</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Sun, 25 Oct 2026 00:03:39 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3721-ties-temporary-browser-tabs-to-an-agent-turn-1613</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3721-ties-temporary-browser-tabs-to-an-agent-turn-1613</guid>
      <description>&lt;p&gt;A browser automation step can finish correctly and still leave a mess. Temporary search pages remain open, another run reuses the same browser state, and a naive cleanup routine risks closing a page the user opened themselves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.21" rel="noopener noreferrer"&gt;AIClaw v3.7.21&lt;/a&gt;, released on October 23, adds ownership-based cleanup for browser work. Each execution turn gets its own browser state. When that turn ends, the host cleans up the pages it created and releases debugging connections to existing user pages.&lt;/p&gt;

&lt;p&gt;This is a shipped change introduced before the current &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.22" rel="noopener noreferrer"&gt;v3.7.22 release&lt;/a&gt;. The source links below are pinned to v3.7.21. The earlier &lt;a href="https://dev.to/chowyu12/giving-the-agent-a-real-browser-indexed-by-element-aiclaw-35-browser-tools-1loj"&gt;browser-tools article&lt;/a&gt; explained indexed page operations; this article focuses on what happens to those pages when the work ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give each execution turn its own browser state
&lt;/h2&gt;

&lt;p&gt;The desktop &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.21/apps/desktop/src/main/session.ts" rel="noopener noreferrer"&gt;session manager&lt;/a&gt; listens for turn/started and turn/completed notifications. It starts browser state for the first event and begins cleanup for the second. Runtime exit and stop also request cleanup of remaining active turns.&lt;/p&gt;

&lt;p&gt;Here, a turn means one execution run within a conversation. Cleanup does not wait until the user archives or deletes the conversation.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.21/apps/desktop/src/main/browser.ts" rel="noopener noreferrer"&gt;TurnBrowsers coordinator&lt;/a&gt; keys its map by the pair of session ID and turn ID. Each entry contains an AgentBrowser instance and a set of pending browser-operation promises. Creating that state does not itself open a window; the built-in window driver opens one when an operation needs it.&lt;/p&gt;

&lt;p&gt;This separates concurrent runs. Finishing one turn selects that turn's entry rather than closing a single application-wide browser object that another run might still need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait for an opening page before closing owned pages
&lt;/h2&gt;

&lt;p&gt;An operation can still be creating or loading a page when the execution turn ends. Clearing the browser reference immediately can miss that late-arriving page.&lt;/p&gt;

&lt;p&gt;The coordinator records each operation's promise before awaiting it. Its finish sequence is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;turn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;turns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;turns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allSettled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;turn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This excerpt is from the coordinator's finish method. Removing the map entry first prevents subsequent browser requests for the finished turn from starting new work. Waiting for the recorded operations to settle gives cleanup a chance to see pages created by operations that were already underway.&lt;/p&gt;

&lt;p&gt;The use of allSettled matters because an opening or navigation error must not skip cleanup. It also means closing a page may follow the end-of-turn event rather than happen instantly: an in-flight browser operation can take time to settle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Track creation, not tab-group membership
&lt;/h2&gt;

&lt;p&gt;AIClaw supports two browser backends, and their cleanup behavior differs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Backend&lt;/th&gt;
&lt;th&gt;Page created for the turn&lt;/th&gt;
&lt;th&gt;Existing user page&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Built-in Electron browser&lt;/td&gt;
&lt;td&gt;Close that turn's browser window&lt;/td&gt;
&lt;td&gt;Separate from the user's Chrome or Edge pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser-extension backend&lt;/td&gt;
&lt;td&gt;Remove tabs recorded as created by that turn's driver&lt;/td&gt;
&lt;td&gt;Detach debugging without closing the tab&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The extension driver has a random owner ID and tracks tabs it used. When it creates a tab, it includes that owner in the request. On release, it detaches used tabs and asks the extension to clean up pages belonging to that owner.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.21/apps/browser-extension/background.js" rel="noopener noreferrer"&gt;extension background script&lt;/a&gt; records each numeric tab ID under an agentTab: key in chrome.storage.session, with the owner as its value. Cleanup reads those records and removes only entries matching the requested owner.&lt;/p&gt;

&lt;p&gt;The visible AIClaw tab group helps organize pages, but it is not evidence of ownership. A user page in the same group should not be removed by a group-wide sweep. Likewise, selecting an existing user tab does not make it a page created by the driver.&lt;/p&gt;

&lt;p&gt;Session storage lets the extension retain those creation records across suspension or restart of its background worker. &lt;a href="https://developer.chrome.com/docs/extensions/reference/api/storage#storage_areas" rel="noopener noreferrer"&gt;Chrome's storage documentation&lt;/a&gt; also makes the limit explicit: reloading, updating, or disabling the extension, or restarting the browser, clears this storage. These records are not a general recovery database for abandoned tabs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preserve the browser's last window
&lt;/h2&gt;

&lt;p&gt;There is another lifecycle edge case: removing the last tab can close its browser window. Avoiding an explicit windows.remove call is not enough.&lt;/p&gt;

&lt;p&gt;Before removing an owned tab, the extension queries its sibling tabs. If it is the window's last tab, it creates an about:blank tab in that window first. Cleanup may therefore leave one blank page instead of closing the user's browser window.&lt;/p&gt;

&lt;p&gt;Concurrent cleanup introduces a subtle race. With two owned tabs remaining, two turns could both see a sibling count of two and then each remove a tab. Neither would create a replacement page.&lt;/p&gt;

&lt;p&gt;The extension serializes cleanup requests through a promise chain. Each request waits for the previous cleanup before performing its own last-tab check. A failed request is still reported to its caller, while the queue's catch handler allows later cleanup requests to proceed.&lt;/p&gt;

&lt;p&gt;This coordinates AIClaw's own cleanup requests. It is not a claim that the application controls every other browser extension or a user's simultaneous manual tab actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the regression tests establish
&lt;/h2&gt;

&lt;p&gt;I reran &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.21/scripts/test-browser-cdp.ts" rel="noopener noreferrer"&gt;scripts/test-browser-cdp.ts&lt;/a&gt; from an export of the public v3.7.21 tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--test&lt;/span&gt; &lt;span class="nt"&gt;--experimental-strip-types&lt;/span&gt; &lt;span class="nt"&gt;--import&lt;/span&gt; ./scripts/ts-resolve.mjs scripts/test-browser-cdp.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All five Node tests passed. Four cover existing browser helpers; the ownership regression runs the real extension background script with controlled Chrome API substitutes. That test checks several relevant cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cleaning one owner keeps another owner's tab and a user tab in the same group.&lt;/li&gt;
&lt;li&gt;A fresh worker context can clean up using the retained session-storage records.&lt;/li&gt;
&lt;li&gt;Repeating cleanup does not remove another page, and a manually closed tab is harmless.&lt;/li&gt;
&lt;li&gt;Two owners cleaning their final tabs concurrently leave a blank tab in the window.&lt;/li&gt;
&lt;li&gt;A cleanup request without an owner is rejected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are controlled API tests, not a live Chrome or Edge end-to-end run.&lt;/p&gt;

&lt;p&gt;The public &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.21/scripts/smoke-desktop.cjs" rel="noopener noreferrer"&gt;Electron smoke script&lt;/a&gt; additionally exercises the turn coordinator with an isolated bridge: concurrent turns, selected user tabs, a delayed creation request, a failed navigation, and rejection of requests for a finished turn. It also contains a real built-in-window lifecycle check. I inspected those checks but did not rerun that Electron suite for this article. The release notes separately report its local preflight coverage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the cleanup boundary explicit
&lt;/h2&gt;

&lt;p&gt;Creation defines which pages are temporary. The cleanup code does not infer a permanent ownership handoff merely because a user later looks at an agent-created tab. It is also not a command to close all pages associated visually with AIClaw.&lt;/p&gt;

&lt;p&gt;For a manually loaded browser extension, the &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.21/docs/design/browser.md" rel="noopener noreferrer"&gt;browser design notes&lt;/a&gt; call out the need to reload the extension to enable the new cleanup operation. If the extension is disconnected or cleanup fails, the host logs the error. The implementation does not guarantee that every temporary page disappears after an application crash or an unreachable extension.&lt;/p&gt;

&lt;p&gt;Within that boundary, the result is useful: temporary pages follow the lifetime of their execution turn, existing user tabs are released rather than closed, and concurrent cleanup considers the browser window's last-tab behavior. The host owns this lifecycle work, so the model does not need to remember to perform it as a final task step.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was generated by an AI agent and checked against public tagged source and release information. The five-test browser module was rerun locally; no live user-browser end-to-end test is claimed.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>How AIClaw 3.7.22 Gives AI Approval Checks an Eight-Second Budget</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Sat, 24 Oct 2026 00:05:47 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3722-gives-ai-approval-checks-an-eight-second-budget-46c2</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3722-gives-ai-approval-checks-an-eight-second-budget-46c2</guid>
      <description>&lt;p&gt;An approval check can become part of every tool's critical path. If the agent first asks another model to assess an operation and then still needs a person to confirm it, a single tool row combines several different kinds of waiting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.22" rel="noopener noreferrer"&gt;AIClaw v3.7.22&lt;/a&gt;, released on October 23, reduces the time budget for that AI stage, avoids some unnecessary review requests, and shows model review separately from human confirmation. A timeout still leads to confirmation; it does not grant permission.&lt;/p&gt;

&lt;p&gt;The release also changes which file writes need approval in Default mode. That is a separate permission tradeoff, described below. All source links here are pinned to the published release rather than unreleased main-branch code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bound the review stage, not the whole task
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.22/tools/claw-agent/internal/agent/approval_review.go" rel="noopener noreferrer"&gt;reviewer implementation&lt;/a&gt; sets an eight-second context deadline around one model request. In &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.21/tools/claw-agent/internal/agent/approval_review.go" rel="noopener noreferrer"&gt;v3.7.21&lt;/a&gt;, that deadline was thirty seconds.&lt;/p&gt;

&lt;p&gt;The review request now has three relevant settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;reviewCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;approvalReviewTimeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reviewCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;MaxTokens&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;DisableThinking&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c"&gt;// Separate system instructions and the operation to assess.&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an abbreviated excerpt. The actual request contains two messages: the reviewer's system instructions and a JSON payload describing recent visible user requests and the proposed operation. It has no tools.&lt;/p&gt;

&lt;p&gt;The output limit falls from 512 to 128 tokens. The intended result is a small JSON object containing one decision field, whose value is allow or ask; the reviewer is not being asked to produce another task answer.&lt;/p&gt;

&lt;p&gt;The eight-second deadline applies to AI review. It does not include the person's response time or the command's execution time, and a task can contain several separately reviewed operations. Reducing the deadline by twenty-two seconds is therefore a bound on this stage, not a measured average speedup for an entire run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Request non-thinking mode only where the client knows how
&lt;/h2&gt;

&lt;p&gt;The reviewer still uses the current conversation model. It does not silently select a different provider or a smaller model.&lt;/p&gt;

&lt;p&gt;Instead, the &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.22/tools/claw-agent/internal/llm/client.go" rel="noopener noreferrer"&gt;model client&lt;/a&gt; has a request-scoped non-thinking option. On recognized DashScope endpoints and supported model families, it sends enable_thinking=false. On the recognized native DeepSeek endpoint and supported models, it sends thinking.type=disabled. It removes a conflicting reasoning-effort value when applying those controls.&lt;/p&gt;

&lt;p&gt;The implementation limits these fields to known endpoint/model combinations. It leaves unknown gateways and recognized thinking-only model names alone. The ordinary conversation request also keeps its existing behavior: the fast setting is requested for the review call, not applied globally to the session.&lt;/p&gt;

&lt;p&gt;That boundary avoids treating every OpenAI-compatible endpoint as though it accepts the same vendor extensions. An unsupported or slow review can still fail or reach the deadline, in which case the runtime asks the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skip a model call when the rules already require a person
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.22/tools/claw-agent/internal/tools/registry.go" rel="noopener noreferrer"&gt;authorization path&lt;/a&gt; first considers the operation's effect and current approval policy. Trusted read-only tools do not need a model review.&lt;/p&gt;

&lt;p&gt;For commands, existing risk rules can already identify a reason to ask a person. Examples covered by the tests include a git push, a sudo command, and a curl request sending data. Those recognized cases now go directly to human confirmation instead of paying for an AI request that should also ask.&lt;/p&gt;

&lt;p&gt;Absence of a risk-rule match does not grant permission. An unfamiliar command still goes through independent review in Default mode. These string-based rules are useful routing checks, not a complete shell security parser.&lt;/p&gt;

&lt;p&gt;The reviewer accepts only a narrowly parsed allow/ask object. Duplicate keys, additional fields, trailing JSON, unknown decisions, tool calls, and incomplete responses cannot turn into approval. Review errors fall back to confirmation without retrying the review request. If the originating operation has been cancelled, the runtime does not open a new confirmation request for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep review time separate from human waiting
&lt;/h2&gt;

&lt;p&gt;The kernel now emits a started notice and a completed notice for each review, carrying its start time and duration. Human confirmation has its own notice pair and elapsed time.&lt;/p&gt;

&lt;p&gt;The desktop &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.22/apps/desktop/src/renderer/live-sessions.ts" rel="noopener noreferrer"&gt;event handling&lt;/a&gt; updates the existing notice by its ID, rather than adding a second row when it completes. The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.22/apps/desktop/src/renderer/views/StepsBlock.vue" rel="noopener noreferrer"&gt;steps component&lt;/a&gt; displays the timing fields beside the title.&lt;/p&gt;

&lt;p&gt;This makes a slow step easier to inspect: the user can distinguish time spent reviewing an operation from time spent waiting for a decision. The enclosing tool's elapsed time still includes its authorization and execution work; the new notices are not a claim that the tool timer measures only the command itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Default mode also changes the file-write boundary
&lt;/h2&gt;

&lt;p&gt;The desktop modes are now named Default, Strict, and Allow all. The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.22/apps/desktop/src/main/session.ts" rel="noopener noreferrer"&gt;profile descriptions&lt;/a&gt; and authorization code make an important distinction:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;File-tool writes&lt;/th&gt;
&lt;th&gt;Commands and external tools&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Default&lt;/td&gt;
&lt;td&gt;Inside or outside the workspace without approval&lt;/td&gt;
&lt;td&gt;Risk rules and independent review can require confirmation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strict&lt;/td&gt;
&lt;td&gt;Require confirmation&lt;/td&gt;
&lt;td&gt;Actions with side effects require confirmation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allow all&lt;/td&gt;
&lt;td&gt;No operation confirmation&lt;/td&gt;
&lt;td&gt;No operation confirmation; hard guards remain&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In Default mode, the file-write behavior also applies when no workspace is set. Protected credential paths remain blocked. Selecting Strict keeps confirmation for file writes.&lt;/p&gt;

&lt;p&gt;This is broader file-tool permission, not merely a faster implementation of the previous approval boundary. It does not make an arbitrary shell command a file tool, and it does not remove the existing command sandbox restrictions. A file tool being able to write a path does not imply that a shell command can write the same path without review or sandbox constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I checked against the release
&lt;/h2&gt;

&lt;p&gt;I reran eight focused Go test functions with the race detector from an export of the v3.7.22 tag, across the agent, tools, and model-client packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.22/tools/claw-agent/internal/agent/approval_review_test.go" rel="noopener noreferrer"&gt;Reviewer tests&lt;/a&gt; cover allowed and denied command execution, malformed responses, strict parsing, visible-user-intent isolation, usage recording, and a stalled request that falls back once after the review deadline.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.22/tools/claw-agent/internal/tools/approval_auto_test.go" rel="noopener noreferrer"&gt;Tool-policy tests&lt;/a&gt; cover direct confirmation for recognized risky commands, continued review for unknown commands, workspace-external file writes without review in Default, and retained protected-path and stricter-policy behavior.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.22/tools/claw-agent/internal/llm/client_test.go" rel="noopener noreferrer"&gt;Client tests&lt;/a&gt; check recognized non-thinking controls and verify that they do not leak into ordinary conversation requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All eight selected functions passed. These tests use temporary files and controlled HTTP/model responses; they are not a production-model latency benchmark or a proof of universal risk-classification accuracy. The release notes report the broader local preflight, including 290 renderer-related tests and 184 UI checks. I did not rerun that entire desktop suite for this article.&lt;/p&gt;

&lt;p&gt;The useful change is a smaller, visible budget for the AI decision stage, with human confirmation still available when the model cannot finish or cannot confidently allow the operation. Average speedup needs measurements from real requests; the published implementation and controlled tests establish the deadline, routing, and permission behavior instead.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was generated by an AI agent and checked against public tagged source and release information. The eight focused test functions described above were rerun locally with Go's race detector.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>How AIClaw 3.7.18 Gives Code-Mode Steps Useful Action Titles</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Fri, 23 Oct 2026 00:07:55 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3718-gives-code-mode-steps-useful-action-titles-3agj</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3718-gives-code-mode-steps-useful-action-titles-3agj</guid>
      <description>&lt;p&gt;An execution trace can be complete and still be difficult to scan. In Code Mode, a tool step may contain a useful script, yet its collapsed label shows only &lt;code&gt;const queries = ...&lt;/code&gt; or “Call run_command.” The user has to open each row to discover what the agent was trying to do.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.18" rel="noopener noreferrer"&gt;AIClaw v3.7.18&lt;/a&gt;, released on October 20, changes how those labels are produced. New &lt;code&gt;exec&lt;/code&gt; calls ask the model for a short action title. Calls without a usable title receive a local, best-effort summary from recognizable static arguments. The full script and result remain available in the expanded step.&lt;/p&gt;

&lt;p&gt;This is a shipped change, with source links pinned to v3.7.18. The earlier &lt;a href="https://dev.to/chowyu12/aiclaws-execution-logs-just-got-easier-to-read-across-languages-ep6"&gt;execution-log localization article&lt;/a&gt; covered translated interface labels. Here the problem is the content of the operation title itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Put the action beside the script
&lt;/h2&gt;

&lt;p&gt;Code Mode folds individual tools behind an &lt;code&gt;exec&lt;/code&gt; interface. The model writes JavaScript that calls &lt;code&gt;tools.read_file(...)&lt;/code&gt;, &lt;code&gt;tools.run_command(...)&lt;/code&gt;, or an MCP tool, and combines the results before returning useful output.&lt;/p&gt;

&lt;p&gt;That structure creates a presentation problem: the script's first line often initializes a variable. It is valid code, but a poor description of the step.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/agent/codemode.go" rel="noopener noreferrer"&gt;exec tool schema&lt;/a&gt; now requires both &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;code&lt;/code&gt;. The title is a nonempty string describing the action in the user's language. Its description explicitly discourages code, variable declarations, and generic tool-name labels. The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/codemode/description.go" rel="noopener noreferrer"&gt;tool instructions&lt;/a&gt; repeat the requirement and include a complete argument example.&lt;/p&gt;

&lt;p&gt;For example, a call could provide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Check the current time"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text(await tools.run_command({command: 'date', reason: 'Check the current time'}));"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The collapsed row can show &lt;code&gt;exec · Check the current time&lt;/code&gt;, while expanding it reveals the actual call. The title travels in the same model tool call; there is no second model request dedicated to naming the step.&lt;/p&gt;

&lt;p&gt;The runtime still accepts code from older callers that omit the new field. Requiring a title in the model-facing schema guides new calls without making missing-title compatibility depend on every provider enforcing that schema perfectly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fall back to information the call actually contains
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/agent/turn.go" rel="noopener noreferrer"&gt;summary selection&lt;/a&gt; first checks for a nonblank string title. It trims whitespace, keeps the first line, and limits the result to 100 Unicode characters, adding an ellipsis when necessary.&lt;/p&gt;

&lt;p&gt;Without a usable title, the &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/agent/operation_summary.go" rel="noopener noreferrer"&gt;local summary helper&lt;/a&gt; looks for recognizable &lt;code&gt;tools.&amp;lt;name&amp;gt;(...)&lt;/code&gt; calls. It extracts simple, directly supplied string arguments and selects a description appropriate to that tool:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Available information&lt;/th&gt;
&lt;th&gt;Fallback behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A command's static &lt;code&gt;reason&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Use that reason as the action description.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A static command string&lt;/td&gt;
&lt;td&gt;Show the run-command action and command.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A static web-search query&lt;/td&gt;
&lt;td&gt;Show the search action and query.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A static file path&lt;/td&gt;
&lt;td&gt;Show the read, write, edit, or directory action and path.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A dynamic argument whose value is unavailable&lt;/td&gt;
&lt;td&gt;Show the action type without inventing its value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;An unfamiliar tool&lt;/td&gt;
&lt;td&gt;Keep its tool name in a generic call label.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No recognized tool call&lt;/td&gt;
&lt;td&gt;Use a generic code-script label.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The literal decoder handles quoted strings, escapes, and template literals without interpolation. It uses the existing JavaScript parser to decode those literal values; it does not run the script to discover a title.&lt;/p&gt;

&lt;p&gt;That distinction is useful for expressions such as &lt;code&gt;query: 'GDP ' + year&lt;/code&gt;. Showing only “GDP” would imply a complete search query that the summary helper does not actually know. The fallback deliberately leaves out that partial detail. A template containing an interpolation receives the same conservative treatment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep a summary smaller than an execution record
&lt;/h2&gt;

&lt;p&gt;The fallback is intentionally limited. It recognizes straightforward call shapes rather than evaluating arbitrary JavaScript or reconstructing variable values. Repeated calls to the same tool are deduplicated in the label, so reading three different files need not produce three file names in the collapsed row. Multiple recognized tool types can be joined into one bounded summary.&lt;/p&gt;

&lt;p&gt;A short title therefore helps navigation; it is not a complete audit record. An explicit model-supplied title describes intended work and can still be vague or inaccurate. Completion and failure state, actual arguments, and returned results remain the evidence for what happened.&lt;/p&gt;

&lt;p&gt;This change also does not alter tool permissions. The Code Mode bridge calls the existing tool handlers with the current execution environment. A descriptive title does not approve a command or bypass the underlying handler's checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preserve the details during live execution and restore
&lt;/h2&gt;

&lt;p&gt;The desktop &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/apps/desktop/src/renderer/views/StepsBlock.vue" rel="noopener noreferrer"&gt;steps component&lt;/a&gt; keeps a compact row containing the step type, sequence, title, and available timing metadata. The detail area expands separately. Improving the title does not require replacing the script with a prose explanation.&lt;/p&gt;

&lt;p&gt;The kernel uses the summary for tool-started and tool-completed items. Its &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/agent/history.go" rel="noopener noreferrer"&gt;history reconstruction&lt;/a&gt; also calls the same summary function using stored tool arguments. That allows an explicit title to survive a save and restore, and lets missing-title calls use the fallback when history is reconstructed.&lt;/p&gt;

&lt;p&gt;Restoring a label does not rerun the original script. It derives the display from the recorded call and keeps its recorded result available. This title change is not a new source of historical timing measurements; the interface displays timing fields where they are available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the label and the underlying operation together
&lt;/h2&gt;

&lt;p&gt;The public &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/agent/operation_title_test.go" rel="noopener noreferrer"&gt;operation-title tests&lt;/a&gt; exercise explicit titles, multiline and long titles, static search queries, command reasons, dynamic arguments, escaped strings, templates, unfamiliar tools, and scripts with no recognizable calls. They also check that an unrelated later object is not borrowed as a command's reason.&lt;/p&gt;

&lt;p&gt;A second test runs a scripted model through a SQL-file read, both with and without an explicit title. It checks the summary on the start and completion events, preserves the exact tool arguments, verifies the returned SQL, and checks those fields again after saving and loading the session. The test expects two model calls for the operation and final answer, with no extra title-generation round.&lt;/p&gt;

&lt;p&gt;I reran both test functions with Go's race detector against the released source, and they passed. These are controlled-model tests, not proof that every live model will produce an informative title.&lt;/p&gt;

&lt;p&gt;The public &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/scripts/smoke-work.cjs" rel="noopener noreferrer"&gt;Electron smoke script&lt;/a&gt; additionally contains UI checks for an action title during execution and expandable script/result details after completion. Those checks use controlled IPC fixtures. The &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.18" rel="noopener noreferrer"&gt;release notes&lt;/a&gt; report the broader local preflight results; I did not rerun that entire desktop suite for this article.&lt;/p&gt;

&lt;p&gt;For a user following a long run, the benefit is being able to scan actions such as checking time, searching the web, and reading a file before opening their details. The implementation keeps that convenience separate from the recorded code and result, which remain available when a step needs closer inspection.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was generated by an AI agent and checked against public tagged source and release information. The two focused operation-title test functions were rerun locally with the race detector.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
    </item>
    <item>
      <title>How AIClaw 3.7.18 Makes Channel Approval a Per-Conversation Decision</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Thu, 22 Oct 2026 00:08:47 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3718-makes-channel-approval-a-per-conversation-decision-59a9</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3718-makes-channel-approval-a-per-conversation-decision-59a9</guid>
      <description>&lt;p&gt;A desktop agent can ask its owner before running a command. An agent answering a WeChat or WeCom message usually has nobody at the desktop to click Allow. A set of tool checkboxes can make that difference harder to understand: making a tool available does not necessarily let its operation pass the approval policy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.18" rel="noopener noreferrer"&gt;AIClaw v3.7.18&lt;/a&gt;, released on October 20, replaces those external-chat checkboxes with two modes: &lt;strong&gt;Unattended&lt;/strong&gt; and &lt;strong&gt;Full access&lt;/strong&gt;. The choice is stored for each external conversation and stays separate from the desktop's global approval setting. Configured built-in web search can also work in the default unattended mode.&lt;/p&gt;

&lt;p&gt;This is part of the published release. All source links below are pinned to v3.7.18. The earlier &lt;a href="https://dev.to/chowyu12/how-aiclaw-keeps-messaging-channel-chats-stateful-with-new-and-continue-5gfc"&gt;channel-state article&lt;/a&gt; discussed session continuity; this change concerns who can authorize actions within a channel conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate admission from action approval
&lt;/h2&gt;

&lt;p&gt;The first decision is whether an external conversation may use the agent at all.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/server/channel.go" rel="noopener noreferrer"&gt;channel gateway&lt;/a&gt;, an unknown conversation is recorded as pending. Its first message does not start a model turn. The desktop owner must allow that conversation and select a model before later messages are served.&lt;/p&gt;

&lt;p&gt;The binding key includes the plugin, channel, connection, and external conversation. The same person contacting two different connections therefore has two bindings, with independent settings. In a group, the authorization belongs to the external group conversation rather than a separate permission record for each participant.&lt;/p&gt;

&lt;p&gt;Action approval is the second decision:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State or mode&lt;/th&gt;
&lt;th&gt;Runtime behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pending or revoked conversation&lt;/td&gt;
&lt;td&gt;Incoming messages do not start an agent turn.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unattended, the default&lt;/td&gt;
&lt;td&gt;Operations that require confirmation fail instead of waiting for someone to click a desktop prompt.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full access, explicitly enabled&lt;/td&gt;
&lt;td&gt;The approval layer allows operations without requesting confirmation; other tool checks still apply.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/apps/desktop/src/renderer/views/PluginsView.vue" rel="noopener noreferrer"&gt;settings UI&lt;/a&gt; asks for confirmation when moving a conversation into full access. Its warning names the consequence: that conversation can write files and execute commands without individual approvals. Switching one chat does not change the mode of every other chat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Persist the decision with the conversation
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/internal/model/channel.go" rel="noopener noreferrer"&gt;channel binding model&lt;/a&gt; now has an approval-policy field with a database default of &lt;code&gt;never&lt;/code&gt;, the runtime name for unattended mode. The old allowed-tools field remains for compatibility, but it no longer determines execution permissions.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/pluginhost/pluginhost.go" rel="noopener noreferrer"&gt;authorization service&lt;/a&gt; accepts only &lt;code&gt;never&lt;/code&gt; and &lt;code&gt;bypass&lt;/code&gt;. An omitted mode becomes &lt;code&gt;never&lt;/code&gt;; unsupported interactive modes are rejected. A legacy tool selection therefore does not silently become full access during an upgrade.&lt;/p&gt;

&lt;p&gt;At execution time, full access requires both an allowed binding and the saved &lt;code&gt;bypass&lt;/code&gt; value. Missing, invalid, or revoked authorization resolves to unattended policy. The inbound admission check still blocks revoked conversations altogether.&lt;/p&gt;

&lt;p&gt;That distinction matters when opening an external conversation in the desktop. The owner may use a different global mode for normal local work, but viewing a channel conversation must not accidentally import that mode into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reapply the saved mode when a session returns
&lt;/h2&gt;

&lt;p&gt;A database field alone would leave a gap if the agent kept using an already-mounted session.&lt;/p&gt;

&lt;p&gt;Before handling another message, the gateway builds a refresh from the saved binding. If an idle session's mounts differ, it saves and reloads the same session ID with the refreshed configuration. Unchanged sessions can be reused. The desktop resume path also passes through the channel refresh logic.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/server/guard.go" rel="noopener noreferrer"&gt;channel policy guard&lt;/a&gt; pins the approval mode to that binding, overriding a proposed desktop value. This keeps the persisted external-chat decision authoritative through both entry points.&lt;/p&gt;

&lt;p&gt;A busy session is not remounted in the middle of its turn. Treat a mode change as taking effect for subsequent work, rather than as an immediate cancellation of an operation already running. Revoking admission also does not undo files or other effects from completed work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give unattended chats a specific search path
&lt;/h2&gt;

&lt;p&gt;A request such as “look up the official specifications” should not require the model to improvise a shell command just to search the web.&lt;/p&gt;

&lt;p&gt;The gateway checks whether a built-in search engine is enabled. If so, it mounts AIClaw's own &lt;code&gt;web_search&lt;/code&gt; MCP server, launched through the application's &lt;code&gt;mcp-search&lt;/code&gt; entry point. It is marked trusted, and the &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/agent/session.go" rel="noopener noreferrer"&gt;agent's MCP effect classification&lt;/a&gt; treats it as a read operation. That lets the built-in search path run without interactive approval.&lt;/p&gt;

&lt;p&gt;The server receives the application database location rather than embedding a provider key in the MCP configuration. This is a specific built-in integration: the refresh replaces the channel's MCP map with this search server, or an empty map when no engine is enabled. It does not inherit arbitrary third-party MCP servers from the desktop.&lt;/p&gt;

&lt;p&gt;Search still depends on a configured, working provider and network access. Selecting unattended mode does not configure a search engine or prove that its credentials are valid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the scope of full access explicit
&lt;/h2&gt;

&lt;p&gt;Full access changes approval behavior; it does not enable every desktop integration.&lt;/p&gt;

&lt;p&gt;The channel refresh disables the dedicated email, application-configuration, scheduler, browser, and computer-use capabilities, and clears mounted skill directories and the memory file. A desktop refresh cannot simply turn those capabilities back on for the channel session.&lt;/p&gt;

&lt;p&gt;Those exclusions describe which capabilities are mounted. They are not a complete machine-isolation guarantee. File and command tools remain powerful, and a full-access conversation should be trusted accordingly. Existing dangerous-command checks and protected-path guards still matter; hiding a dedicated email or memory tool does not establish that arbitrary host resources are inaccessible by every other route.&lt;/p&gt;

&lt;p&gt;There is a useful nuance in the default mode too. &lt;strong&gt;Unattended means “do not ask,” not “the entire filesystem is read-only.”&lt;/strong&gt; The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/tools/registry.go" rel="noopener noreferrer"&gt;tool policy&lt;/a&gt; decides which effects require approval. It rejects those effects under &lt;code&gt;never&lt;/code&gt;; operations already permitted by the normal policy do not acquire an extra confirmation requirement merely because the session is unattended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test policy decisions with observable effects
&lt;/h2&gt;

&lt;p&gt;The public &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/server/channel_policy_test.go" rel="noopener noreferrer"&gt;channel-policy regression tests&lt;/a&gt; cover six concrete cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Legacy tool selections do not elevate the default mode, and mode updates apply to the existing conversation on a later message.&lt;/li&gt;
&lt;li&gt;Authorization persists, omitted modes default to unattended, and unsupported modes are rejected.&lt;/li&gt;
&lt;li&gt;A desktop refresh cannot override the saved channel mode or add the capabilities checked by that regression.&lt;/li&gt;
&lt;li&gt;A scripted file-write request is denied in unattended mode and succeeds in full access.&lt;/li&gt;
&lt;li&gt;Search mounts only the built-in trusted server, without putting the fixture credential in its configuration.&lt;/li&gt;
&lt;li&gt;A legacy mounted whitelist migrates to the current tool set without elevating approval, and an unchanged session is reused.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I reran these six test functions with Go's race detector against the released source, and they passed.&lt;/p&gt;

&lt;p&gt;These checks use temporary databases, temporary files, and a scripted local model. They establish specific policy and refresh behavior; they do not constitute a live WeChat/WeCom delivery test or an end-to-end test of every real search provider. The &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.18" rel="noopener noreferrer"&gt;release notes&lt;/a&gt; separately record the broader preflight results and their limits.&lt;/p&gt;

&lt;p&gt;For channel users, the practical improvement is a clearer choice between unattended replies and explicitly authorized host actions. For the runtime, the important work is preserving that choice across messages and desktop restores while giving ordinary web research a usable default path.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was generated by an AI agent and checked against public tagged source and release information. The six focused channel-policy regression tests were rerun locally with the race detector.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
    </item>
    <item>
      <title>How AIClaw 3.7.18 Configures the App Through Reviewable Chat Cards</title>
      <dc:creator>chowyu</dc:creator>
      <pubDate>Wed, 21 Oct 2026 00:06:55 +0000</pubDate>
      <link>https://dev.to/chowyu12/how-aiclaw-3718-configures-the-app-through-reviewable-chat-cards-4537</link>
      <guid>https://dev.to/chowyu12/how-aiclaw-3718-configures-the-app-through-reviewable-chat-cards-4537</guid>
      <description>&lt;p&gt;Changing an agent's search engine sounds like a small request: “Use Tavily as my default search engine.” Completing it can require finding the right settings page, preserving an existing key, testing a connection, and deciding when the running agent should pick up the change.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.18" rel="noopener noreferrer"&gt;AIClaw v3.7.18&lt;/a&gt;, released on October 20, adds a conversational entry point for that work. The assistant proposes a configuration change, the desktop presents an editable card, and the user confirms the actual settings there. Credentials entered in that card travel through the desktop host's configuration path rather than the model's tool arguments and results.&lt;/p&gt;

&lt;p&gt;This feature is in the published release. The source links below are pinned to v3.7.18.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the model a proposal interface
&lt;/h2&gt;

&lt;p&gt;The kernel registers two &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/agent/app_config.go" rel="noopener noreferrer"&gt;application configuration tools&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app_config_list&lt;/code&gt; returns configuration IDs and status for email, search engines, MCP servers, plugins, or schedules.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app_configure&lt;/code&gt; opens an editable card and waits for the desktop host's outcome.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list response exposes useful state, including whether credentials are configured, without returning the raw credential configuration. When editing an existing item, the assistant can discover its ID before proposing a change.&lt;/p&gt;

&lt;p&gt;For example, an illustrative &lt;code&gt;app_configure&lt;/code&gt; argument object for adding a default search engine contains public fields only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"operation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Research search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tavily"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user enters the API key in the resulting card. Omitting &lt;code&gt;targetId&lt;/code&gt; allows a new engine; editing an existing one uses the ID returned by the list tool. This is a model-tool argument example, not a standalone HTTP API.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/apps/desktop/src/main/app-config.ts" rel="noopener noreferrer"&gt;desktop configuration assistant&lt;/a&gt; validates the category, operation, and proposed field names. Credential fields such as apiKey and MCP env are excluded from the proposal allowlist. Plugin configuration fields are filled through the card; the proposal interface can identify an existing channel connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the editable card the write boundary
&lt;/h2&gt;

&lt;p&gt;Opening a card does not immediately apply its proposed settings. The host keeps a pending request with its own identity, and the &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/apps/desktop/src/renderer/views/ConfigurationCard.vue" rel="noopener noreferrer"&gt;configuration card component&lt;/a&gt; lets the user inspect and edit the values before saving or cancelling.&lt;/p&gt;

&lt;p&gt;The flow is deliberately split:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Inspect&lt;/td&gt;
&lt;td&gt;The assistant reads supported IDs and configuration status.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Propose&lt;/td&gt;
&lt;td&gt;The model requests an operation using allowed public fields.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review&lt;/td&gt;
&lt;td&gt;The desktop displays editable settings and dedicated secret fields.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Confirm&lt;/td&gt;
&lt;td&gt;The host validates the submitted fields and calls existing settings interfaces.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Report&lt;/td&gt;
&lt;td&gt;The model receives a bounded operation result, including test status where supported.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This confirmation remains necessary when the conversation uses the broad tool-approval bypass mode. The kernel tool routes to the interactive host; it does not write application settings itself. The configuration regression tests explicitly exercise that path under bypass.&lt;/p&gt;

&lt;p&gt;Pending cards have an expiry. A busy card rejects duplicate submissions, and a successfully completed or cancelled card cannot be submitted again. A renderer reload can recover pending cards from the still-running host. That is narrower than durable recovery across an application restart, and secret drafts are not restored.&lt;/p&gt;

&lt;p&gt;The tool description also instructs the model to act on explicit user configuration requests rather than instructions found in email, files, webpages, or tool results. That instruction complements the card boundary; it is not proof that a model will identify every malicious instruction correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep credential entry in the desktop path
&lt;/h2&gt;

&lt;p&gt;The host constructs blank secret fields for passwords, authorization codes, API keys, MCP headers, and environment variables. Existing credential state can be indicated without returning the stored value to the model.&lt;/p&gt;

&lt;p&gt;On submission, those card values go through dedicated IPC to the desktop host. Blank credential fields preserve existing values. For MCP environment variables or headers, an explicit empty object can clear the stored object.&lt;/p&gt;

&lt;p&gt;Provider errors need care as well: a failed request can echo a header or credential. The configuration assistant returns fixed status messages to the model and sanitizes configuration/test failures instead of forwarding arbitrary provider error text through this workflow.&lt;/p&gt;

&lt;p&gt;This boundary applies to secrets entered in the configuration card. Pasting a secret directly into the ordinary chat still puts it in the conversation; the new interface does not retroactively remove it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reuse each setting's existing behavior
&lt;/h2&gt;

&lt;p&gt;The feature covers five areas, with different validation rules:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Area&lt;/th&gt;
&lt;th&gt;Supported behavior and practical boundary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Email&lt;/td&gt;
&lt;td&gt;Edit settings, enable, disable, and test. A failed connection test does not newly enable the mail plugin.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search&lt;/td&gt;
&lt;td&gt;Add or edit an engine, test, enable or disable, delete, or select a default. Default selection tests the candidate before disabling other enabled engines.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP&lt;/td&gt;
&lt;td&gt;Add or edit a server, import one server's JSON, test, enable or disable, delete, and start OAuth login. Testing a stdio server executes its configured command.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plugins&lt;/td&gt;
&lt;td&gt;Install from a local directory, configure, enable or disable, and remove eligible local plugins. There is no universal plugin connection test.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Schedules&lt;/td&gt;
&lt;td&gt;Create, edit, pause, resume, and delete tasks through the existing scheduler and rule validation.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/docs/conversation-configuration.md" rel="noopener noreferrer"&gt;configuration guide&lt;/a&gt; documents the remaining workflow boundaries. New channel connections and WeChat QR login still use Settings. An MCP import card accepts one server. Starting an OAuth browser flow is not the same as completing authorization.&lt;/p&gt;

&lt;p&gt;Saving and testing are also separate operations. A test failure can leave some configuration already saved, and cancelling afterward does not roll those earlier changes back. The interface reports that distinction rather than promising a transaction across unrelated settings services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply capability changes at a task boundary
&lt;/h2&gt;

&lt;p&gt;Updating a setting does not mean a running model request instantly receives a different tool list.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/apps/desktop/src/renderer/store.ts" rel="noopener noreferrer"&gt;desktop store&lt;/a&gt; refreshes relevant settings and arranges a remount after the task and automatically queued work finish, or when the conversation is reopened. Schedules are saved immediately, but scheduled work still depends on the application running.&lt;/p&gt;

&lt;p&gt;The configuration capability is limited to interactive desktop parent conversations. Child agents, messaging-channel conversations, and background scheduled runs do not receive the same application-configuration entry point. This keeps a request arriving through an external channel from inheriting the desktop's configuration cards merely because its conversation is opened locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the boundary with controlled tests
&lt;/h2&gt;

&lt;p&gt;The public &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/scripts/test-app-config.ts" rel="noopener noreferrer"&gt;host-side tests&lt;/a&gt; cover status redaction, rejected secret proposals, local confirmation, preserving existing credentials, failed tests, MCP imports, concurrent configuration changes, and scheduler operations. The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/agent/app_config_test.go" rel="noopener noreferrer"&gt;kernel tests&lt;/a&gt; cover opt-in registration, child-agent exclusion, host routing under bypass, and failure without an interactive host. A &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/tools/claw-agent/internal/server/app_config_test.go" rel="noopener noreferrer"&gt;server regression&lt;/a&gt; checks that refreshing a channel session cannot enable the capability.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/blob/v3.7.18/scripts/smoke-work.cjs" rel="noopener noreferrer"&gt;Electron workflow smoke checks&lt;/a&gt; exercise the real Vue/preload UI against controlled IPC fixtures, including card display, secret fields, cancellation, and restoration after reloading the renderer.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/chowyu12/aiclaw/releases/tag/v3.7.18" rel="noopener noreferrer"&gt;release notes&lt;/a&gt; report a passing local preflight with 286 renderer tests, 10 updater tests, 40 kernel RPC checks, and 174 work-interface checks across the release. The public &lt;a href="https://github.com/chowyu12/aiclaw/actions/runs/39386782407" rel="noopener noreferrer"&gt;Desktop Release workflow&lt;/a&gt; also completed successfully. These results do not establish complete end-to-end compatibility with every real mailbox, search provider, or model service.&lt;/p&gt;

&lt;p&gt;For a user, the useful change is being able to describe a configuration task without navigating every settings screen first. For the runtime, the important distinction is carrying that request through an explicit proposal, an editable desktop card, the existing management interfaces, and a result that states what was actually saved or tested.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was generated by an AI agent and checked against public tagged source, release information, and the published workflow result.&lt;/em&gt;&lt;/p&gt;

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