# Qoder
# What is Qoder
> Learn how the Qoder product family brings agentic capabilities to software development, everyday work, and enterprise operations.
Qoder is an **agentic platform for real work**. It brings AI into software development, terminal workflows, managed cloud execution, everyday productivity, and long-running digital roles.
Instead of stopping at a suggestion or chat response, Qoder is designed around an end-to-end loop: understand the task and its context, plan the work, use tools to execute it, verify the result, and iterate toward the requested outcome.
## Core ideas
### Context engineering
Give agents persistent context from code, knowledge, rules, tools, files, and the working environment so they can understand real tasks accurately and continuously.
### Agent autonomy
Let agents understand intent, make decisions, use tools, and carry out multi-step work independently while retaining necessary review points.
### Goal-oriented loop
Move from a stated goal through planning, execution, verification, and iteration until the requested deliverable is ready.
These foundations support capabilities such as multi-agent collaboration, Memory and Rules, Skills and plugins, comprehensive context, and Repo Wiki. The exact experience depends on the Qoder product you use.
## One product family, several ways to work
A dedicated agentic development workspace. Use Editor for in-flow assistance and Quest for long-running, multi-step delegation.
Bring code suggestions, Ask, Agent, MCP, and project rules into supported JetBrains IDEs.
Work with a coding agent from the terminal, and extend it into scripts, automation, and development workflows.
Run managed agents through APIs by configuring Agents and Environments, starting Sessions, and streaming results.
Delegate document, spreadsheet, research, browser, and desktop tasks and receive usable local deliverables.
Create digital employees called Wakers for ongoing responsibilities, conversations, automations, and multi-stage flows.
Monitor supported IDE and CLI tasks, review plans, and handle approvals away from your computer.
Add centralized purchasing, members, identity, policies, knowledge, models, marketplace, audit, and other governance controls.
## Get started
Choose a product based on your goal, then continue to its authoritative setup guide and complete a first useful task.
Follow new features, improvements, and fixes across Qoder products.
See how teams and individual builders use Qoder in real projects.
Compare individual plans, then review Credits and billing behavior before estimating usage.
# AMAP Automotive AI Native Engineering in Practice | Building Business Knowledge Engineering with Qoder
> The AMAP Automotive AutoSDK team turned domain knowledge into an engineering asset that can be produced, tuned, automatically refreshed, and consumed with Qoder's knowledge engine, lifting the strict one-shot rate from 37.3% to 61.5%.
Title: A Record of AI Native Evolution in AMAP Automotive Engineering | Building Business Knowledge Engineering with Qoder
Author: AMAP Automotive Business
Abstract: AMAP's enterprise business built a "production, tuning, refresh, consumption" system for business knowledge with Qoder's knowledge engine. The same class of error no longer happens twice, and the one-shot task pass rate rose from 37.3% to 61.5%.
> *AutoSDK is AMAP's in-vehicle SDK product for the automotive industry.* It spans more than a million lines of code across twenty-odd Git repositories. With Qoder's knowledge engine, we built a "production, tuning, refresh, consumption" system for business knowledge. The same class of error no longer happens twice, and the one-shot task pass rate rose from 37.3% to 61.5%.
The ceiling on AI Coding capability **lies not in the model itself, but in domain knowledge**. KoCo-Bench measurements bear this out: general-purpose programming clears 90% Pass\@1, while domain code generation reaches only 8.9%. Adding domain knowledge retrieval under an Agent paradigm lifts that to 34.2%, with a peak of 62.5% in the best track (arXiv:2601.13240v3).
The practice of the AMAP Automotive AutoSDK team confirms this judgment. Our AI coding already runs as an engineering discipline, with requirement comprehension, solution design, code output, and self-testing connected end to end. Yet the stability of single-pass generation, or one-shot, remained the weak link, surfacing as four classes of failure: **exploration drift** (sinking deeper in the wrong direction), **generation deviation** (produced code diverging from the intended implementation), **architecture violation** (ignoring established layering and module conventions), and **constraint omission** (missing implicit dependencies or cross-module relationships). Root-cause analysis converged sharply: the meaning of business terms, the boundaries of module responsibility, the trade-offs behind historical decisions. None of this domain knowledge had ever been structured into a form AI could consume. **The knowledge gap is the real bottleneck for stability.**
Our goal, therefore, was to upgrade the domain knowledge dormant in code and experience into **an engineering asset that AI can perceive, consume, and evolve**. The vehicle is Qoder's knowledge engine: code output becomes capture, AI coding becomes consumption, and practical validation becomes feedback, forming a loop that keeps appreciating in value rather than a static document that is outdated the moment it is finalized.
## 1 | Layers and Boundaries
For the loop to run, knowledge first needs a map: how many layers there are, where each one lives, and where the boundary of this article is drawn.
AutoSDK's domain knowledge is a full spectrum running from low-level code facts up to top-level constraints and preferences. We divide it into four layers by degree of abstraction, and the relationship among them maps onto the DIKW spectrum of cognition.
**L1 Code and configuration (the Data layer)**: the raw facts underlying all knowledge. Everything above is distilled from it, and whenever knowledge conflicts with code, the code always wins.
**L2 Terminology and processes (the Information layer)**: core terms, module information, and critical paths.
**L3 Business domain knowledge (the Knowledge layer)**: responsibility boundaries, architectural rules, and the reasons behind the status quo, helping the Agent understand the business as a whole and avoid design drift.
**L4 Constraints and preferences (the Wisdom layer)**: this layer covers how something should be written and why it is written that way. It holds design constraints, solution preferences, key decisions, API design methodology, and more. Its reach is broad and it is triggered often, so precision is what matters.
The relationship among the four layers runs both ways. **Bottom-up, each layer distills the one below it**, since all upper knowledge is abstracted from lower knowledge. **Top-down, each layer guides execution**: AI reads the L4 constraints first, then consults L3 and L2 to understand the current state, and finally lands at L1 to write code. At the same time, the higher the layer, the more it depends on people, and the lower the layer, the more it depends on the engine.
This article focuses on engine-led factual knowledge (L1 through L3). It can be distilled in bulk and refreshed automatically alongside the code, giving it **broad coverage at low maintenance cost**, and it solves the problem of **not being able to see the current state clearly**. L4 leans on human judgment and forms a system of its own, so it is out of scope here.
## 2 | The Knowledge Lifecycle
From first output to continuous appreciation, knowledge goes through a complete lifecycle: upfront intervention delivers the first production run, sustained downstream tuning carries it from cold start to steady-state operation, practice identifies which high-value knowledge deserves priority, and a freshness mechanism keeps it current.
### 2.1 First Production: Upfront Intervention and Calibration
Turn the knowledge engine loose without drawing boundaries and it will partition knowledge by code structure rather than business structure, producing a pile of cards that are too coarse, vaguely bounded, and redundant with one another. Once that misalignment is captured, reworking it later costs more than starting over, because you first have to correct every place AI misread, one by one.
Using Qoder's /knowledge-plan command, we have AI perform a full scan of the repository and generate a draft production plan, which people then review and revise: aligning business boundaries, removing ambiguity and redundancy, and adding missing dimensions. The result is a production blueprint AI can read, one that provides direction and dimensional guidance rather than the final knowledge content.
The value of upfront intervention is this: code can only state the structural fact of what exists here, while the business perspective of how to look at it has to be injected by people in advance. In essence, it turns the business understanding inside experts' heads into a blueprint that precedes AI knowledge production.
### 2.2 Tuning and Revision: From First Polish to Bad Case Closure
Getting it right the first time depends on exhaustive foresight, which is expensive and fragile. Risk inside a complex system can never be fully enumerated, and any unanticipated edge condition is enough to break through.
Downstream tuning runs in three steps with Qoder's /knowledge command: identify, organize, write. We pin down what needs improvement and attribute it to specific cards, AI gathers the code facts and upstream and downstream relationships, organizes them into a structured draft, and finally writes them into the knowledge base.
**Cold start**: concentrated polishing right after the first output. Once the engine has produced in bulk, people run a dedicated review pass over the entire body of knowledge, checking whether boundaries align with business structure, whether terminology is accurate, and whether redundancy or contradiction exists across cards, correcting the systematic drift of automated distillation in one concentrated effort. Once the first batch of business requirements enters AI coding, bad cases expose blind spots in dense succession, and this is when revision frequency peaks.
**Steady-state operation**: bad cases drive routine revision. Misread terminology during requirement comprehension, module drift during exploration, architecture violations during design, hallucinated output during coding, all of it signals missing knowledge. The response is a fixed three steps: locate, revise, regress. Regression is not about whether a human can follow the text, but about returning to the original task to verify that AI corrects its behavior, and anything that fails goes back for another round. Internally we commit to closing every bad case the same day.
**Bad cases are not the only thing worth capturing. Information from good cases that came at a high exploration cost deserves capture just as much.** An implicit dependency that took the Agent fifteen rounds to locate, for instance, makes that very path the knowledge for next time. Failure drives us to close gaps and expensive success drives us to cut cost, and together the two push the knowledge base toward maturity.
### 2.3 What to Capture: Criteria for High-Value Knowledge
After the production and tuning described above, a higher-order question gradually surfaces: plenty of knowledge is worth capturing, but which deserves investment first? You cannot fully enumerate the types of high-value knowledge at the outset. Only once the Agent genuinely drifts off course in the same direction repeatedly can you confirm there is a pitfall there. There is only one criterion: without this knowledge, the Agent will most likely drift or pay an excessive exploration cost. The inverse matters just as much. Knowledge that the code already expresses clearly, and that the Agent can reach cheaply, does not need separate capture. Simple utility function signatures or standard library usage, for example, are documented by the code itself, and writing another knowledge card is pure redundancy.
In practice we converged on four categories most worth prioritizing. What they share is that code cannot provide a reliable answer:
- **The panorama of complex business logic**: the full path is scattered across multiple files. Without knowledge the Agent explores divergently at high and volatile cost, and with knowledge it converges quickly onto a precise track.
- **Hidden pitfalls in the code**: code fragments that look alike are the most likely to confuse the Agent. Here knowledge acts as a guardrail for crossing the pitfall smoothly, flagging in advance the paths that look right but are actually wrong.
- **Distinguishing business terminology**: terms established by convention lack explicit definitions in code, so an Agent search returns nothing but superficially similar answers. Capturing them moves the Agent from needing human correction to passing on the first round.
- **Cross-repository paths**: data paths spanning multiple Git repositories, as in AutoSDK's lane-level map layer business. Exploration cost is extremely high, and scenarios where the call chain breaks, such as thread switches and message dispatch, are especially hard for AI to explore. A knowledge card belongs to a single repository while describing cross-repository information, which preserves the per-repository organizing framework while restoring the implicit path across the break.
These four categories were all discovered the same way: identified and recorded only after a concrete bad case exposed them. What gets captured is not designed, it is learned the hard way.
### 2.4 Staying Fresh: Hook-Triggered Automatic Updates
Code changes every day, and no one can watch it line by line. We packaged knowledge refresh as a Skill and bound it to the development process through a WebHook on the code platform: a merge into the trunk triggers a callback that spins up an Agent, the Agent pulls the diff for that merge, and QoderCLI completes the incremental knowledge update automatically, with the result pushed to developers as a single message. **Knowledge updates are driven by code change events**, refreshing on merge, unattended most of the time, with intervention only when something goes wrong.
### 2.5 Collaboration Mechanisms and Evolution
For the tuning and automatic freshness above to work, there is an implicit prerequisite: knowledge for the same module is not rewritten by several people at once. Reality does not always cooperate.
The cloud side of Qoder's knowledge engine currently uses overwrite-based updates, so in concurrent editing the later write overwrites the earlier one, and capabilities such as review, staged rollout, and rollback are not yet available. Our interim approach routes each module's knowledge through a single Owner, trading parallel efficiency for consistency. As Qoder's knowledge engine progressively supports concurrent editing and version management, efficiency and consistency will eventually come together.
## 3 | Knowledge Consumption
### 3.1 One Source, Many Outlets
AutoSDK has four kinds of knowledge consumers: AI Agents need structured recall, developers use document search, non-development roles ask about the business without reading code, and external teams integrate through an existing platform. The temptation to write a separate version for each is always there, but **the drift and contradiction that follow forking are more fatal than the maintenance cost**.
We hold just one line: **a single body of knowledge serves both people and AI, never forked**. From one source we open different outlets: developers use RepoWiki, AI recalls through SearchMemory, non-developers read QMind online, and external teams sync to KBase through the CLI or API. The first three are produced by Qoder's knowledge engine from the same source and therefore never diverge, while KBase slots into the existing pipeline unobtrusively, forcing no one to change habits.
### 3.2 Recall Across Nested Repositories
Nested repositories are everywhere in AutoSDK, with component repositories embedded inside the main project. A developer opens the project in the main repository while component-level knowledge sits scattered across sub-repositories, and if recall stops at the workspace boundary, the earlier production investment is reduced to zero.
We first hit this in a nested component requirement: the Agent searched for knowledge in the main repository and got nothing but main-repository overviews, finding nothing about the key logic living in a sub-repository, so developers had to switch workspaces by hand and the AI coding workflow degraded completely. Qoder's nested recall capability, which lets you configure whether sub-repository knowledge is recalled by the parent directory repository, upgrades knowledge reachability from workspace-bound to repository-structure-bound: open the project in the main repository, and recall covers knowledge cards in both the main repository and every embedded sub-repository, with no switching required.
### 3.3 Knowledge Consumption in the AI Coding Workflow
AutoSDK's AI coding workflow follows a plan-act pattern overall, and one wrong step during planning means rework for everything after it. Without agreed timing and objectives for recall, knowledge is merely a static asset. Qoder's built-in SearchMemory tool indexes knowledge cards, and each stage of the pipeline has a different recall objective:
- **Requirement comprehension**: recall knowledge using keywords from the PRD such as interface names, protocol names, functional concepts, and terminology, then assess how well it matches. Strong matches enter the component candidate set and are cross-checked against AGENTS.md, while weak matches and misses are ignored, which prevents misread terminology from routing work to the wrong component.
- **Exploration**: first recall background such as module architecture, coding patterns, and technical constraints using the exploration topic and target component as keywords, then begin searching code. Every time a key new symbol appears, such as a core class name, a critical interface, or an unexpected dependency, immediately recall its responsibilities and its upstream and downstream relationships. Recall does not block the search and a miss does not impede progress, but a hit narrows the search space substantially and avoids blind traversal.
- **Solution design**: hold to dual-source fusion, with research leading and knowledge supporting. First recall domain background and evolution direction using domain terminology, key function names, and historical design strategies, retrying with different wording on a miss up to a set limit. Then launch a code investigation and cross-check the prior knowledge against the code on the ground, which avoids design drift.
What matters in knowledge consumption is which stage, which keywords, and to what end. Only once recall is embedded as a fixed action does knowledge genuinely participate in decisions.
## 4 | Evaluating the Results
We evaluate the knowledge system from two angles. **The case view dissects how knowledge corrects bad cases through concrete business scenarios. The data view quantifies the measured gains before and after adoption under a controlled definition.**
### 4.1 The Case View: How Knowledge Corrects Bad Cases
The two representative cases below both follow the same structure: scenario, deviation without knowledge, knowledge intervention, root-cause takeaway.
#### Case One: A Missed Panorama of Complex Business Logic
**Scenario**: a large-scale refactor of a business component, involving process changes and the retirement of legacy components, with wide-reaching impact.
**Deviation without knowledge**: AI touched only the component implementation and missed the bound callback parameters and the associated business interfaces. The change looked complete while the path was in fact broken, and because nothing failed immediately, it surfaced only during integration testing, requiring a backward trace across several files to locate what had been left unchanged.
**Knowledge intervention**: with panoramic business knowledge, AI enumerated the component implementation, callback parameters, and associated business interfaces completely in one pass, correctly drew the boundary against similar components, and finished the refactor in a single attempt with no manual patching.
**Root-cause takeaway**: the panorama of complex business logic is scattered across many files and call sites, so capturing a view such as "component equals implementation plus style callbacks plus business interfaces" as knowledge is precisely how the most easily missed implicit context gets delivered up front.
#### Case Two: Semantic Confusion Among Similar Structs
**Scenario**: add a standalone highlight effect for the target lane, with its own color scheme and animation, fully separated from the existing ego-lane highlight.
**Deviation without knowledge**: three similarly named objects in the code belong to different semantic dimensions, namely target lane style, ego lane style, and adjacent vehicle target marker. AI conflated all three: it first judged the target lane style to be nonexistent and applied the ego lane style instead, then treated the adjacent vehicle target's isHighlight field as a lane highlight switch, requiring the user to paste header files repeatedly across several rounds of correction.
**Knowledge intervention**: with terminology knowledge, AI clarified everything in one pass, that StyleA and StyleB are independent structs and must never be reused, and that the isHighlight field is a marker at the adjacent vehicle target level and has nothing to do with lane highlighting. It completed the change directly, with no manual code pasting needed.
**Root-cause takeaway**: the fact that similar naming does not mean identical semantics cannot be read out of code. Capturing the semantic distinctions among similar objects and the separation of cross-dimensional concepts as knowledge blocks interference-type bad cases at the source.
### 4.2 The Data View: Investment and Measured Gains
The case view answers how knowledge works, and the data view answers whether the investment is worth it.
**Cost**: for first production, an average of two hours per repository to complete planning and proofread the production blueprint, with 20-plus business component repositories covered on a weekly cadence. For routine maintenance, driven by bad cases, the analysis, revision, and regression loop for a single piece of knowledge closes within hours.
**Primary metric**: the strict adjusted one-shot rate, defined tightly. The denominator is tasks that produced code changes within a given period, and the numerator is tasks completed in a single query where 80% of the code was neither rolled back nor modified within 30 minutes. It measures **whether AI can grasp the business panorama and its details well enough to get the task right the first time**.
After the knowledge system was adopted, the team ran 120-plus tasks in real day-to-day business, spanning simple, medium, and complex difficulty levels and covering requirement types from new features to changes in existing ones. Using this batch as the basis, we ran both a stage comparison before and after adoption and a controlled comparison within the same window based on whether knowledge was actually recalled.
#### Stage Comparison: Before and After the Knowledge System
Taking adoption as the dividing line, the **strict one-shot rate rose from 37.3% to 61.5%** afterward, and the **average number of conversation rounds per completed task fell from 3.49 to 2.53**. This shows that knowledge not only raised the share of tasks done right the first time, but also lowered the cost of iteration.

#### Controlled Comparison: With and Without Knowledge Recall in the Same Period
The stage comparison above is influenced by multiple factors such as time trends and task composition. To isolate the effect of knowledge itself more directly, we grouped tasks within the same period by whether knowledge was actually recalled. The recall group's interaction path was **39% shorter on average**, most pronounced in scenarios that demand a great deal of implicit context, such as complex tasks and large codebases, consistent with the original intent of lowering exploration cost and filling in the business panorama.
It should be noted that these statistics come from real operation, the sample carries distribution bias and fluctuation introduced by changes in member tasks, and whether knowledge was recalled also correlates with task difficulty, knowledge richness, and Agent behavior, so the conclusions are stronger in direction than in absolute value. Even accounting for all of this interference, however, the stage trend and the same-period controlled comparison point to the same signal: **the translation of knowledge into results is positive and observable**.
## 5 | The Threshold from Usable to Trustworthy
This is AMAP AutoSDK's domain knowledge engineering practice built on Qoder's knowledge engine, spanning knowledge production, tuning, refresh, and consumption. The measured data shows the system lifted the strict one-shot rate from 37.3% to 61.5%, cut average conversation rounds by nearly 30%, and shortened the interaction path by 39% for the group where knowledge was recalled.
Qoder's knowledge engine provided the critical support for this practice: /knowledge-plan aligns boundaries up front and removes ambiguity and redundancy before bulk production, /knowledge tunes the knowledge problems that practice exposes, and the built-in SearchMemory tool recalls knowledge cards precisely during requirement comprehension, exploration, and solution design. Native platform support for nested repository recall and for one source with many outlets (RepoWiki, KnowledgeCard, QMind) lets a single source of knowledge serve people and AI at once, avoiding the fatal cost of version drift.
The core of domain knowledge engineering is not how many documents you write, but making sure the same class of error never happens twice. Once your team reaches that point, AI Coding crosses the threshold from usable to trustworthy.
## 6 | Four Directly Reusable Recommendations for Enterprises Industrializing AI Coding
If your team is also pushing AI Coding toward an engineering discipline, these four points are what we would most want to tell ourselves in advance, after the pitfalls we walked into:
**Recommendation one: map your knowledge layers before you discuss tooling.** Do not start by rolling out an AI assistant. Spend 30 minutes drawing your team's L1 to L4 map first: what the code already expresses (L1), what is scattered terminology (L2), what is the business panorama (L3), and what are design constraints (L4). Once the layers are clear, tool selection converges on its own: hand L1 to L3 to Qoder's knowledge engine for bulk distillation, and leave L4 to senior engineers writing Skills and AGENTS.md. Steer clear of the myth that one large model solves everything.
**Recommendation two: start the mechanism with same-day bad case closure, not with a complete knowledge base.** Perfectionism is the biggest enemy. Set one iron rule on day one: every bad case in AI Coding gets located, revised, and regression-verified the same day, without exception. Even if only five knowledge cards are captured in the first week, stick with it for three months and you will have a knowledge base with a high signal-to-noise ratio. That is ten times more effective than quietly writing 200 pages of documentation.
**Recommendation three: keep only the knowledge that code cannot express and exploration cannot reach cheaply.** Filter with a simple rule: if AI can figure it out within three minutes of reading code, do not write it; if AI took fifteen rounds to locate it, or if similar names make it easy to confuse, you must write it. The four categories worth prioritizing are the complex business panorama, hidden pitfalls in code, terminology distinctions, and cross-repository paths. Everything else is noise.
**Recommendation four: one source, one version, held from day one.** Do not maintain two copies just because people and AI read different formats. Pick one source, such as Qoder RepoWiki, as the single source of truth, and derive everything from it, whether AI consumption, developer lookup, or external inquiries. Forking feels good briefly, and then drift buries you.
# Qoder Assistant Group Chat Q&A Bot User Manual
> Qoder Assistant is a group chat Q&A bot that answers only from your knowledge base, privately checks with the colleagues you designate whenever it is unsure, and turns every confirmed answer into new knowledge.
## 1. What Is Qoder Assistant
Qoder Assistant is your team's **group chat Q\&A bot**. Once it joins a group chat, team members simply ask their questions in the group and Qoder Assistant answers automatically. It has three defining characteristics:
- **Grounded answers only**: it answers strictly from the knowledge base you provide, and never makes things up
- **Asks when unsure**: when it runs into a question it is not confident about, it proactively checks with the colleagues you designate
- **Gets smarter with use**: answers confirmed by colleagues accumulate automatically and are reused directly next time
## 2. Creation and Configuration
### 2.1 Creating Qoder Assistant
Open the QoderWake console, click "Create Waker", choose the **"Qoder Assistant (Q\&A Bot)"** template, fill in a name and description, and you are done.
After creation, the detail page displays a configuration guide. Just follow the prompts step by step.
### 2.2 Connecting to Group Chats
Open the Qoder Assistant detail page, select "IM" in the left sidebar, and go to the IM channel configuration page.
**Supported channels:**
- DingTalk (Alibaba team accounts support the AliDing bot only)
- Lark (currently under internal security review and not yet available)
**Steps to connect:**
1. Click the "Configure" button for the channel you want
2. Fill in the App ID and App Secret (or choose QR code mode)
3. Click "Add Pairing", select the channel, and fill in the pairing details:
- **Conversation information**: choose "Direct Message" or "Group Chat" as needed. For direct messages, providing the Open ID is recommended; if no Open ID is provided, a User ID is required; the display name is optional
- **Runtime configuration**: select the model and working directory as needed; if no working directory is selected, the default IM working directory is used
4. Click "Create Pairing", then turn on the channel switch to activate it
> **Qoder Assistant uses workflow mode by default, with no manual selection required.** The Open ID identifies a user within the current application, while the User ID is the account identifier inside your company or organization. Once pairing is complete, messages automatically enter the preset Q\&A flow.
After connecting, group members just ask questions as usual, with no extra steps required. Multiple channels can be connected at the same time.
### 2.3 Configuring the Knowledge Base
The knowledge base is the source of evidence for every answer Qoder Assistant gives. Qoder Assistant acquires knowledge by **binding** knowledge bases available on the platform.
**Steps:**
1. Open the Qoder Assistant detail page, select "Knowledge Base" in the left sidebar, and click "Bind Knowledge Base"
2. Choose "Select Existing" to bind a knowledge base already on the platform, or choose "Create and Bind" to create a new one
3. Multiple knowledge bases can be bound
**Knowledge base content management** happens in the platform-level "Knowledge Base" module (the knowledge base icon in the left navigation bar), where you can upload files, enter URLs, add entries manually, and more.
> **Recommendation**: first create and upload your team's existing FAQ documents in the Knowledge Base module, then come back here and bind them.
### 2.4 Asking Colleagues for Help
When Qoder Assistant encounters a question the knowledge base does not cover, it automatically sends a direct message to the colleagues you designate to confirm the answer.
Select "Team Collaboration" in the left sidebar, click "Add Colleague", search by name or employee ID, and fill in the collaboration settings:
- **Areas of expertise**: for example "reimbursement, attendance"; Qoder Assistant routes questions by matching these areas
- **Role**: technical owner, business owner, and so on
- **Permission checkboxes**: enabled, can confirm answers, can be asked for help
The page shows how many questions are currently awaiting confirmation and how many are complete, making it easy to track progress.
### 2.5 Reply Requirements
Manage Qoder Assistant's reply behavior on the "Settings" page in the left sidebar:
- **Reply style**: professional and measured / concise and direct / lively and upbeat, chosen to match the tone of the group
- **Reply language**: follow the user / always Chinese / always English
- **Business scope**: tell Qoder Assistant which kinds of questions it is responsible for (it declines anything out of scope)
- **Sensitive information**: define the content types it must never reply with (such as account credentials); when encountered, it directs the user to contact the owner
- **Disclaimer**: can be enabled for external groups, appending a disclaimer to the end of every reply
## 3. How It Works
Everything Qoder Assistant does is driven by a **preset WakerFlow workflow**. When you create a Qoder Assistant, the system initializes this default flow automatically.
### Default Flow Logic
Once a group message arrives, WakerFlow makes decisions in the following order:
1. **Primary decision**: determine the message intent, whether it is a legitimate question, noise, out of scope, or an expert reply
2. **Task execution**:
- Legitimate question, then search the knowledge base, then reply if an answer is found
- No match in the knowledge base, then escalate to an expert request, then send a direct message to the relevant colleague
3. **Expert reply handling**: the colleague confirms the answer, then it is posted back to the original group automatically, then the knowledge is stored
**The core loop:** question, knowledge base search, ask a colleague when unsure, capture the confirmed answer as knowledge, answer directly next time.
The longer it is used, the more questions Qoder Assistant can answer on its own, and the less often it needs to interrupt colleagues.
### Viewing and Editing the Workflow
Open the Qoder Assistant detail page and select the "Workflow" tab in the left sidebar to see the workflow script:
- **Canvas**: view the entire flow structure visually and modify nodes by dragging
- **Script**: edit the JavaScript code directly
- **Run history**: review how each group message was processed and how long each step took
Beyond the default Q\&A flow, you can also **create new WakerFlows of your own** so Qoder Assistant handles more custom tasks, such as summarizing unresolved questions into a daily report, or checking on a schedule whether the knowledge base has gone stale. Click the "New WakerFlow" button and define the flow either through conversational editing of designated canvas nodes or by writing the script by hand.
> **Tip**: if you do not need a custom flow, leave the default as is. The default flow already covers the vast majority of group chat Q\&A scenarios.
## 4. Reviewing Results
### Q\&A Records
The "Q\&A Records" section in the left sidebar presents Qoder Assistant's operating data: total questions, reply rate, help requests, and failures. Filtering by group chat is supported. It makes clear at a glance which kinds of questions go unanswered, so you can top up knowledge exactly where it is needed.

## 5. FAQ
| Question | Answer |
| --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Are Qoder Assistant's answers accurate? | Qoder Assistant answers from knowledge base content first and hands off questions it is unsure about to colleagues for confirmation. That said, it is powered by a large language model, so we recommend piloting it with a small group, observing answer quality, and then expanding usage. |
| Can I use it without a technical background? | Yes. The knowledge base only requires uploading documents, and the remaining settings can be completed step by step by following the guide on the home page. |
| Does it support questions asked with images? | It can receive images, but it currently relies mainly on the text within them. Complex interfaces, charts, or questions conveyed by an image alone may be misunderstood, so adding a text description is recommended. |
| Will it interrupt colleagues too often? | Once a given type of question is confirmed, it is captured as knowledge and will not be routed again. Routing rules can be adjusted in the collaboration settings. |
| What should I do if an answer is inaccurate? | Add or correct the relevant content in the knowledge base, or adjust the business scope description under "Settings". |
| How do I review answer quality? | Check "Q\&A Records" in the left sidebar, where you can filter question counts, reply rate, help requests, and other metrics by group. |
| I added the bot, but the group chat list is empty. What now? | This usually means DingTalk event subscription was not configured successfully. Delete the current DingTalk channel, run `qoderwake channel dingtalk qr-start`, authorize by scanning the QR code with DingTalk on your phone, and add the new bot to the group chat. The QR code flow configures event subscription automatically. |
| A direct message request failed with `HTTP 403 - IpNotInWhiteList`. What now? | Open the corresponding application on the DingTalk Open Platform and add the egress IP of the server running QoderWake to the allowlist under "Permission Management / Development Configuration" or "Application Security Settings". |
| My original knowledge base disappeared after an update. Is the data lost? | The knowledge base is still associated with your platform account and no data has been lost. After upgrading to the latest version, simply bind the original knowledge base again. |
| A DingTalk document link returns 404 after being added to the knowledge base. What now? | DingTalk documents are access restricted and cannot be bound and read directly as a knowledge source. Export it to a supported file format and upload that, or convert it into publicly accessible content before importing. |
| Qoder Assistant answered with out-of-scope content or content from another version. What now? | Define the business scope and applicable version explicitly under "Settings", and bind only the knowledge bases for the matching product and version. Clean up or refresh outdated content promptly to reduce irrelevant recall. |
| How do I diagnose an abnormal answer? | Go to "Workflow, then Run History" to review how the message was processed, what the knowledge base recalled, and which tools were called, then adjust the knowledge base or reply settings based on what you find. |
# 400 Business Scenarios, 300 Agents: How a Retail Company Built Its AI Platform
> Kidswant used Qoder to shorten a week-long full-stack requirement to one day and build Zhishu, an AI platform running 400 business scenarios and 300 agents.

## While Others Added AI to Their Businesses, Kidswant First Made Its R\&D Team AI Native
> *Many companies talk about AI transformation as adding a few AI features to the business. Kidswant took an earlier step: it first made software creation itself AI native. Qoder was the lever.*
### A Full-Stack Requirement Went from One Week to One Day
In the past, implementing an integrated frontend-and-backend business requirement meant that people first broke the requirement into tasks and then wrote the code line by line, with tools providing occasional completions on the side. Kidswant's R\&D team adopted a different approach. Using Qoder, they clearly described the goal and acceptance criteria and built their internal AI platform, Zhishu, shortening delivery from nearly six months to two months.
Qoder is an Agentic coding platform designed for real-world software development. Unlike ordinary code-completion tools, it first understands the entire codebase and then advances tasks systematically, like an engineer. In actual development, several capabilities changed the team's rhythm.
For a system with many modules and intertwined frontend and backend components, the greatest obstacle is not understanding the codebase. Qoder's Repo Wiki automatically organizes the architecture buried in the code into documentation, continuously updates it as the code changes, and can be committed to Git so the entire team shares the same understanding. When developers ask, "How is this implemented?", they can get an answer without searching through the source code. Multiple developers collaborated during the development of Zhishu. Repo Wiki enabled efficient coordination across complex modules and played an especially important role as Agent orchestration and knowledge-base modules were continuously iterated and integrated.
When implementing requirements, the team used Quest Mode. After the goal and acceptance criteria are clearly described, it aligns the scope, designs a solution, writes the code end to end, verifies it, and fixes issues on its own. A full-stack requirement changes files across multiple technology stacks, which is precisely where multi-file modification and long-running execution are valuable. When developing the Skills marketplace for Zhishu, the work involved frontend-backend interaction. After developers clearly described the marketplace's functional requirements and page interactions in Quest Mode, the feature could be completed in about one day.
To ensure that AI-generated code matched the company's business instead of producing boilerplate that required rework, the team packaged coding conventions, business context, and review standards as project-level Skills. Agents then followed those rules automatically when writing and reviewing code. MCP connected Qoder to internal tools and systems.
The significance of this change was not simply how much faster code could be written. The team's default way of working changed from "people write, AI assists" to "people define, AI delivers." That is what AI Native should look like.
### Building More Than Ten Expert Agents Was Like Adding More Than Ten Real Teams
The most important product Kidswant built in this way was Zhishu, its self-developed AI platform. Built on Qwen large language models, Zhishu integrates a knowledge base, workflows, and Skills. It supports multi-Agent collaboration, long- and short-term contextual memory, and interactions through DingTalk, H5, and other channels.
Today, Zhishu runs more than 400 business scenarios and over 300 agents. It has also accumulated more than ten "expert agents" for roles such as data analysis, finance, supply chain, customer service, and content creation. Each corresponds to a real team in the company. Notably, most of the Skills were also created after being optimized with Qoder.

*Zhishu's expert agents cover functions from data analysis to human resources.*
The Super Entry is a company-wide unified entry built on the Zhishu Agent platform and composed of more than ten business expert agents. Kidswant provides the same entry in its internal site employee workbench and its "People and Customers as One" platform.

*Employees sign in to the site workbench and summon any expert agent through the Super Entry.*
The same development approach was reused for the desktop version of Zhishu. Kidswant used Qoder to build macOS and Windows clients with more than 50 internal operations and office Skills. The clients can also run background automation tasks performed by "digital employees."

*The Zhishu client brings AI capabilities from the browser to employees' desktops.*
The results are tangible. Financial reconciliation was reduced from three days of manual work to 20 minutes. Data-analysis efficiency nearly tripled. The intelligent settlement assistant resolves more than half of the issues it handles, and the content-creation expert saves the equivalent capacity of more than 30 employees. More business users are also beginning to define agents and Skills for their own work on the platform.
This creates a closed loop: R\&D uses Qoder to write code; that code builds Zhishu; Zhishu uses Qwen to serve the business; and new business requirements return to R\&D, where Qoder is used again.
More importantly, the content-marketing, supply-chain, and store-operations experts accumulated by Kidswant are fully adapted to the maternal-and-infant retail industry.
### "Can You Use AI?" Became Part of Performance Evaluation
Beyond tools and platforms, Kidswant embedded the transformation in its organization. The CTO and HR organizations led the initiative together, upgrading R\&D collaboration while incorporating the ability to use AI into capability evaluations.
Tools can save time, but what the organization does with that time determines the depth of the transformation. For Kidswant, the development time saved by Qoder became time the team could invest in building platforms, connecting scenarios, and accumulating methodology.
### Final Thoughts
For a retail company, the hardest part is not buying an advanced tool, but turning that tool into an organizational capability. Kidswant is doing the latter.
Several prerequisites from Kidswant's experience are worth considering:
- **What signals indicate that transformation should begin with R\&D?** Business-side AI requirements have been queued for more than three months, R\&D delivery cannot keep up with business demand, and the bottleneck is capacity rather than ideas.
- **How should the first pilot requirement be selected?** Do not choose the simplest one, because it proves little, or the most complex one, because too many variables make failure likely. Choose a requirement with clear boundaries, multiple technology stacks, and a conventional delivery time of about one week.
- **When does Repo Wiki create the most value?** When a codebase has hundreds of thousands of lines, many collaborators, and legacy code that newcomers cannot understand. A small project with two or three developers may not need it.
- **How should the first Agents be selected?** Start with the teams that repeatedly perform the same type of work, rather than with what AI can do. Kidswant mapped every expert agent to a real team—finance to a finance expert, supply chain to a supply-chain expert—so the Agent's boundary, users, and evaluation criteria already existed. Begin with teams that are labor-intensive, rule-driven, and produce standardized outputs.
- **When should the change expand to the organizational level?** Do not declare company-wide AI adoption at the beginning, when there are no successful examples to support it. Establish a benchmark and measurable results first, then introduce organizational mechanisms.
[Contact us for more enterprise solutions ➔](https://page.aliyun.com/form/act465803565/index.htm?spm=a2c7g.act_detail.main.6.21921b90ToNJto)
# Farewell to "Vibe Coding": The Evolution and Practice of Team-Level AI Development Powered by Harness Governance and SDD
> AMAP's evolution and practice of team-level AI development powered by Harness governance and SDD.
Hello everyone. I'm Wang Shuxin from AMAP's Large Model Application Platform. Today I'd like to share a topic titled "Farewell to 'Vibe Coding': The Evolution and Practice of Team-Level AI Development Powered by Harness Governance and SDD."
## 1. Identifying the Three Core Problems of AI Coding
The story starts last September. Back then, I was invited to the Qoder sub-forum at the Yunqi Conference to share our team's experience in improving R\&D efficiency with Qoder. It was a moment full of expectation—leveraging prompt engineering and context engineering, we achieved a 53% AI code-generation rate across the technical-design and development phases. At the time, that number showed us the enormous potential of AI programming.
After more than half a year of rapid AI progress, our team's code-generation rate can now reach 80%–90% and beyond. The number looks great—it has nearly doubled. But when we interviewed the team in depth and reviewed the PMO's data metrics, we discovered a puzzling fact: **the efficiency gains were not obvious.**
The code-generation rate went up, but project delivery cycles didn't shorten noticeably; AI wrote more code, yet developers' workloads didn't decrease. This forced us to stop and think seriously about the problem.
Let me first revisit the core content I shared back then. We identified three problems with AI Coding:
**First, the free-improvisation problem.** AI-generated code is often wildly unconstrained, because of insufficient business understanding and missing conventions. Ask it to build a feature, and it may give you three different implementations—each one "runs," but each may clash with your existing architecture.
**Second, the reduced-efficiency problem.** It sounds contradictory—isn't AI supposed to boost efficiency? But in real use, if your instructions aren't clear enough, you end up going back and forth across many rounds of dialogue. You say "change this," it changes it; you say "no, like this," it changes again. After several rounds, you might as well have written it yourself.
**Third, the lost-key-information problem.** Across multi-turn conversations, AI often "forgets" important constraints stated earlier. When the task granularity is too large, the architectural requirements mentioned at the start vanish by the end.
To address these issues, we proposed a systematic Qoder practice at the time: using Repo Wiki, Memory, and Rules to constrain AI's free improvisation; using prompt engineering to improve efficiency; and using context engineering and Quest mode to avoid losing key information.
At the end of that talk, I was full of expectations for the future of AI programming: in the future, developers would only need to define requirements and validate results, while the "grunt work" of documentation, coding, and testing would be handed to AI. AI would shift from a production tool into a new R\&D infrastructure, and developers would evolve from coders into AI architects. That was the vision back then.
## 2. Looking Beyond "Code-Generation Rate" to the Deeper Dilemma of "Efficiency"
But half a year later, we were confused. Why didn't the higher code-generation rate translate into real efficiency gains? I spent a long time thinking about this, and eventually found three core reasons.
### Reason 1: R\&D Is a Full-Chain Process, Not Just Writing Code
Let's look at the complete chain of a requirement from proposal to launch: product proposal, product-and-engineering review, solution design, development, code review, testing, integration, and launch. Every stage carries communication costs, waiting time, and the possibility of error.
*The Mythical Man-Month* has a famous thesis—there is no silver bullet. Why? Because software development is not just coding; it involves communication, collaboration, and decision-making. If you optimize the coding stage by 50%, but coding is only 30% of the whole chain, then the overall gain is just 15%. What's more, AI-generated code may bring more code-review time, more debugging time, and more rework.
This made me realize: **real efficiency gains must connect the entire chain, not just optimize a single stage.** Therefore, we need AI to cross stage boundaries and form a closed loop from requirement to deployment.
### Reason 2: Vibe Coding on Legacy Applications Is Extremely Risky
What is Vibe Coding? It's "programming by vibes"—casually tossing AI a few prompts and letting it generate thousands of lines of code in seconds. This approach might be fine for new projects or small scripts, but in legacy applications the risk is extremely high.
What characterizes legacy applications? They carry historical baggage, implicit dependencies, and business knowledge embedded in the code. If you let AI "vibe code," it may generate a solution that looks perfect but is completely incompatible with the existing system. Worse, these problems may only surface after going live.
We once ran into a case: AI-generated code changed the parameter order of a core interface, all unit tests passed, but after launch it caused errors in three downstream services. It took an entire day to track down. This drove home a lesson: **in legacy applications, AI programming must move from "vibes" to "conventions," and there must be clear acceptance criteria.**
That is exactly why we introduced SDD (Specification-Driven Development). The core idea of SDD is that before AI writes any code, we must first turn humans' vague ideas into clear, unambiguous, structured specifications, so that AI runs on a controllable track.
### Reason 3: Large Projects and Complex Requirements Exceed the Capability Boundary of a Single AI Conversation
We've encountered requirements like this: a refactoring task involving a dozen front-end and back-end modules. You can't finish it in a single conversation—AI's context window is limited and its attention gets scattered. When the task is too large, AI loses sight of one thing while attending to another.
These three reasons point to the same conclusion: **AI programming must upgrade from a "personal skill" to a "team-level engineering capability," and evolve from "vibe coding" into a "specification-driven, engineering-governed" R\&D paradigm.**
## 3. The Solution: Introducing SDD and Harness
Having clarified the problems, we began looking for solutions. Our goal: let AI improve efficiency not only in the code-writing stage, but across the entire flow from requirement PRD to direct deployment.
We focused on two core ideas: **SDD (Specification-Driven Development)** and **Harness (Harness Engineering)**.
### SDD (Specification-Driven Development)
The core idea of SDD is disruptive: specifications are no longer prose written for humans, but structured "intent code" that AI Agents can precisely understand and execute.
In traditional development, the PRD or design doc is merely a "guidebook," while code is the only "source of truth." This causes documents to quickly become outdated and disconnected from the code. SDD overturns this structure: the specification becomes the single source of truth. When requirements change, developers first modify the "specification," and AI tools then regenerate, validate, and update the underlying code accordingly.
The SDD workflow contains four stages:
**First, Specify.** The developer discusses with AI and produces a structured specification defining user stories, acceptance criteria, and system constraints. This is the "raw requirement" stage.
**Second, Plan.** Like a compiler, AI "compiles" the specification into a detailed technical plan and a task-breakdown list. This is the "technical document" stage.
**Third, Implement.** AI Agents execute the task list one by one, automatically generating high-quality code. This is the "software development" stage.
**Fourth, Validate.** Test cases are automatically generated from the specification and executed, ensuring the generated code fully conforms to the specification. This is the "functional and code-specification testing" stage.
### Harness Engineering
If SDD solves the problem of "what to do," Harness solves the problem of "how to do it controllably."
The word "Harness" is vivid. Picture a wild horse—a large AI model has boundless power, but without a harness you can't even mount it and might get thrown off. The core of Harness Engineering is not to change the horse's genes (the model itself), but to design a precise control system for this wild horse.
A mature Harness system contains four core pillars:
**First, context engineering.** No longer simple RAG (Retrieval-Augmented Generation), but structured information feeding. Maintain a "single source of truth" so the Agent knows the project's directory structure, the current execution plan, and which documents are up to date.
**Second, architectural constraints.** This is the most hardcore part of Harness. Physical means force AI to obey the rules. For example, code in the UI layer is absolutely forbidden from directly accessing the database layer. If AI tries to violate the architectural layering, the code won't even pass syntax checks and is blocked before submission.
**Third, feedback loops and entropy management.** AI will inevitably make mistakes; the key is how to detect and correct them. Build an automated testing sandbox: the Agent writes code → tests run automatically → failure → error logs are read → the Agent self-corrects and retries. More importantly, human bug-fixing experience is solidified into new rules, ensuring AI never makes the same mistake twice.
**Fourth, human oversight.** Humans shift from "the ones who write code" to "reviewers" and "environment designers." Their responsibilities are to define complex business boundaries, handle the 5% of ambiguous logic AI can't judge, and optimize the Harness rules themselves.
From prompt engineering to context engineering to Harness Engineering, this is a paradigm shift: **from "how to talk to AI," to "what AI should see," to "how AI runs in a controlled environment."**
Based on these two core ideas, we began putting them into practice with Qoder.
## 4. Full-Flow Automation in Practice
Below, through a demo, I walk through the complete process of end-to-end development of a large requirement with Qoder.
In the demo, you can see the entire process is fully automated: starting from the requirement PRD, to Spec generation, to task breakdown, to code generation, to test validation, and finally to deployment. Throughout this process, the developer plays the role of requirement clarifier, specification reviewer, and result validator—not code writer.
Next, let me break down the whole practice in detail.
### Step 1: Design the Knowledge Base
The foundation of the entire practice is the knowledge base. We organize knowledge in a three-layer structure: **project layer, technology layer, and asset layer.**
- **Project-layer knowledge** includes the project overview, directory structure, architectural design, technology choices, and so on. These are the basis for AI to understand the project context. Following the idea of on-demand loading, we maintain a top-level README.md file as Qoder's "single source of truth"—if a piece of information isn't in the docs, it simply doesn't exist as far as Qoder is concerned.
- **Technology-layer knowledge** includes general technical knowledge, coding conventions, middleware, third-party library documentation, best practices, and common problem solutions. This knowledge is reusable across projects and reflects the team's technical accumulation.
- **Asset-layer knowledge** includes reusable code snippets, components, templates, historical requirement PRDs, technical solutions, archived test cases, and more. These are the "bricks" the team has accumulated over the years, and AI can use them directly to build new features.
In real projects, docs are organized into directories following the three-layer knowledge-base structure, then indexed through a README.md for on-demand loading. This layered indexing mechanism ensures structured organization of knowledge while enabling the flexibility of on-demand loading, letting the AI agent efficiently obtain the knowledge it needs and avoid context overload.
Here I want to highlight the concept of **Memory**. Memory is a core capability of Qoder that solves AI's "context anxiety." In long-cycle project development, AI needs to remember a lot of information: past decisions, current progress, pending items, and so on. Memory provides a structured way to store and manage this information. Through this Memory system, AI can make the right decisions in the right context, rather than starting from scratch every time.
### Step 2: Handle the Requirement PRD
With the knowledge base in place, the next step is handling the requirement PRD. We use Qoder's Quest Spec mode to generate a standardized design.md document.
This process is not fully automated—it requires human intervention. This is the idea of **HITL (Human-In-The-Loop).**
Why HITL? Because requirement documents contain a lot of "tacit knowledge"—information product managers take for granted but that actually needs clarification. Take the simple feature of "user login": behind it there may be questions like which login methods to support, whether to remember login state, what password-strength requirements exist, how to handle login failures, and so on.
Through Spec mode, AI proactively asks questions, guiding developers to clarify this tacit knowledge and gradually complete a full Spec. A Spec includes:
**Data model**: which tables are involved, what the field definitions are, and what the relationships are.
**Interface specification**: API inputs and outputs, error codes, idempotency requirements, and so on.
**Most importantly: acceptance criteria.** This is the core of SDD. Acceptance criteria must be testable and unambiguous. For example, "the user is redirected to the home page after a successful login" is a vague description, whereas "after a successful login, the user is redirected to the home page within 3 seconds, and the home page displays the user's nickname" is a testable acceptance criterion.
With a complete Spec, AI has a clear "construction blueprint" and is no longer "vibe coding."
### Step 3: The Experts Team Executes Tasks
Once the Spec is ready, we enter the execution phase. We use Qoder's **Experts Mode.**
The core idea of **Experts Mode** is that different tasks are handled by Agents playing different roles—just like a real development team with front-end engineers, back-end engineers, test engineers, architects, and so on.
AI generates an execution plan from the Spec, breaking a large task into manageable subtasks. Each subtask has clear inputs, outputs, and acceptance criteria. Then, based on the task type, it is assigned to an Agent of the appropriate role.
The system comes with five built-in expert types, each with its own toolset, and it also supports custom expert types.
I also want to emphasize the shift in the user's role: the user is part of the coordination loop too. You can step in at any time while the Experts team is running, and the Experts Leader handles it in the next cycle—adjusting task direction or canceling tasks that are no longer needed. Your role has changed: you clarify intent with the Experts Leader, align on direction, review plans, and validate results—much like leading an experienced R\&D squad.
### Step 4: Task Deployment
After code generation and testing pass, we enter the deployment phase. Through the MCP (Model Context Protocol) tools provided by Aone (Alibaba's internal CI/CD platform), we hand the build artifacts to an Ops Agent for deployment.
Through MCP, the Ops Agent can trigger CI/CD pipelines, execute deployment scripts, query deployment status, and handle deployment exceptions. This connects the entire chain from requirement to deployment. Developers no longer need to manually operate various tools—they only make the key decisions under AI's guidance.
For projects that couple front end and back end, we also enabled some extended-tool Skills.
What are Skills? Skills are Qoder's capability-extension mechanism. Through Skills, AI can gain various additional abilities, for example:
Database-operation Skill: AI can directly query and modify the database to prepare and validate data.
With these Skills, AI can complete end-to-end development, testing, and validation—not just the generation of engineering code.
## 5. Summary and Outlook
With the SDD-and-Harness solution, we connected the entire chain from requirement to deployment. More importantly, we achieved a paradigm shift from "vibe coding" to "specification-driven, engineering-governed" development. Developers are no longer passive code writers, but active requirement definers, specification reviewers, and result validators. AI is no longer an uncontrollable black box, but a reliable tool operating under Harness constraints.
Looking ahead, we believe three directions are worth exploring:
**First, smarter Spec generation.** Currently, Spec generation still requires considerable human intervention; in the future we hope to lower that cost through smarter, conversational requirement clarification.
**Second, more powerful Agent Teams.** The collaboration model of Agent Teams is still relatively simple today; in the future we hope to explore more complex modes, such as multi-round iteration and dynamic role assignment.
**Third, more complete knowledge management.** The knowledge base is the foundation of the entire system; in the future we hope to explore smarter mechanisms for knowledge extraction, updating, and reuse.
# One Paragraph Summons 13 "Programmers": Alibaba Qoder's New Mode Lets Me Be a CTO Lying Down
> Qoder's Experts Mode automatically breaks down requirements and dispatches multiple expert Agents to develop in parallel—one paragraph is enough to build and refactor a personal blog.
AI Coding has finally leveled up to collaborative teamwork.
That was my reaction after recently testing **Alibaba Qoder's "Experts Mode."** Under Experts Mode, **Qoder directly organized a cyber engineering team for me**—I just watch, and the expert team does the work.
It automatically parses my requirements, assigns tasks, and dispatches "engineers" with different responsibilities—**frontend, backend, testing, and operations**—driving **multiple agents to advance tasks simultaneously**, letting me be a CTO lying down.
This reflects a new trend in AI Coding: vibe coding is moving toward multi-agent collaborative programming, AI has turned developers into Agent managers, and the AI IDE is becoming an agent-management tool.
## The Qoder Expert Team Speed-Runs a Personal Blog with Me
After opening Qoder in Editor mode, click "Toggle AI Sidebar" in the top-right corner, then click the mode-switch button at the bottom center, and you can use **Experts Mode**.
To quickly test the expert team's capabilities, I chose to start from scratch and build a simple personal blog project. After I entered the project requirements, **the expert team's "commander," the Team Lead, automatically broke my requirements into 8 tasks and dispatched them to different cyber engineers**.
The first one the Team Lead sent out was **general engineer Nick**. He isn't responsible for the actual development—since I currently had only an empty folder and lacked the environment the project needed, Nick first had to install dependencies for me, set up the basic project structure, and initialize the project.
During this process, Nick also ran into some problems, which it overcame on its own.
In the end, Nick smoothly completed the task and reported back to me.
Then Nick handed off the work to his "colleague"—**backend engineer Jimmy**. But unlike a human backend engineer who handles both backend development and the database, Jimmy was only responsible for initializing the database—showing just how fine-grained the division of labor is in Experts Mode.
After Jimmy finished building the database, the project could officially start writing code. The Team Lead divided the work by module among 5 engineers, who were respectively responsible for frontend pages, middleware, and backend API development—very comprehensive.
It looks like a linear process, but in fact multiple engineers were advancing the project at the same time during development. This undoubtedly sped up development efficiency, and it's also one of the advantages of multi-agent collaborative programming under Experts Mode.
After the previous 7 "colleagues" completed development, the project commander Team Lead also arranged for **testing engineer Chris to perform full-process validation**.
Chris directly opened the browser, entered the account and password, logged into the website, and then fully tested the entire create-read-update-delete logic.
At the same time, it automatically saved screenshots of key pages to display the test results.
After the testing was done, the project development still wasn't over—I also had the system review the code quality, so the Team Lead added another expert, **code reviewer Mark, who found multiple system vulnerabilities and even graded them by severity**.
I then had the expert team fix the vulnerabilities. The experts didn't fix them one by one directly; instead, they first analyzed the situation, then found that two tasks had no dependency on each other and could be developed independently, so two experts completed the tasks in parallel—clearly more efficient.
At this point, all development and testing work was complete. With the help of the 8 experts on Qoder's expert team, **it took me just 16 minutes to have a personal blog website**. It has complete create-read-update-delete logic, with a front-end display page and a back-end management page.
But the technical architecture was still rather crude, without frontend-backend separation, so I decided to raise the difficulty and test the expert team's refactoring ability, asking it to refactor the backend using Spring Boot (a Java development framework) and MySQL (a relational database).
## The Expert Team Refactors Together, Building AI Tools with AI
I first, as before, told the Team Lead my requirements. After a feasibility analysis of these requirements, the Team Lead asked me a few questions, each offering three options; after I made my decisions, the Team Lead then dispatched a new expert, Alex.
Alex is a researcher, responsible for analyzing my current project structure and code interfaces, then formulating a complete refactoring plan and writing it into markdown to guide the subsequent spec-driven development.
With the refactoring plan in place, the Team Lead began directing the engineering team to work, and a new role appeared: **operations engineer Nick**, responsible for installing MySQL for me.
After MySQL was installed locally, I worried there might be version conflicts between different components, so I stepped in at this point to raise the question on my mind, and the system gave a reassuring answer. **This is also a feature of Qoder's Experts Mode: developers can step into the process at any time to raise questions or change requirements.**
This design is quite true to life—after all, which developer has never had a product manager tack on extra requirements (doge).
Next came the normal advancement of the project and automatic debugging. Frontend and backend were advanced simultaneously multiple times along the way, and in the end the project was efficiently refactored and the tech stack was rewritten.
**But I didn't stop there.** How can software built by AI Coding not have AI? I again asked the expert team to integrate the Qwen API for me and set a theme, so that AI could directly write articles for me in the future. ~~It's really not so I can slack off later.~~
After receiving my requirements, the Team Lead created a new task and **arranged frontend and backend engineers at the same time** to deliver the feature.
From development to refactoring, I summoned 13 programmers just by moving my lips, completing as many as 30 tasks.
Looking at the entire process, compared with other AI IDEs, Qoder's Experts Mode showed many unique strengths. **So, why do we need an "AI Coding expert team" now?**
**Because AI Coding is ushering in a new paradigm shift.**
## Why Do We Need an "AI Coding Expert Team"?
**"Since last December, AI Coding has undergone a qualitative change"**—this remark by the guru Karpathy recently sparked heated discussion in the industry.
Karpathy once proposed and popularized the concept of "Vibe Coding," and now he has once again perceived a shift in the direction of AI programming. **Karpathy believes that AI programming agents are now far more capable than before and can tackle large projects and long-term tasks.**
This means **AI programming has shifted from Vibe Coding to Agentic Engineering—AI is no longer just simply completing code, but has begun to fully build projects in the form of agents.**
The new paradigm in AI programming has also given rise to new problems.
On one hand, there's the **code quality problem**. Currently many mainstream AI Coding tools are still single-agent-based; they're fine for simple tasks, but once facing complex tasks—such as multi-round iteration or refactoring a project—**their context length may not hold up**, ultimately making development like a bear picking corn: working on the feature at hand while forgetting the earlier tasks, with a fragmented logic chain and worrying code quality in the end.
On the other hand, there's **room to improve efficiency**. Large projects are very complex, involving all kinds of work—frontend UI, backend development, and database design. **Some tasks could clearly be executed separately, and real-world teams often arrange them that way**, but under single-agent programming, you're still forced to wait.
Qoder's Experts Mode happens to solve both pain points of quality and efficiency. From the hands-on experience above, the expert team **isn't simply piling up the number of agents**—it's a **true multi-agent system**. Because the experts it assigned me have different specialties, and as described they actually **work in their own independent contexts**, so with mutual collaboration they can clearly handle more interaction rounds.
To address the context problem, Qoder specially built an engineering knowledge engine—a code cognition system that can use multi-dimensional data sources, integrating your code files, commit history, Repo Wiki, and memory to optimize the experts' ability to deeply understand context.
In addition, during testing I repeatedly found scenarios where multiple experts advanced work at the same time—in which case the experts wrote different pages separately, or developed frontend and backend separately, which undoubtedly sped up the project's progress.
These are the characteristics I've perceived so far. **It's said that the expert team's agents also autonomously learn new Skills, self-evolve, and get smarter and more attuned to me the more I use them.** The new mode just launched, so I haven't discovered this feature yet; I'll share more with everyone when I have the chance.
Overall, Experts Mode speeds up development efficiency and improves code quality. Qoder tested Experts Mode's code quality using an internal complex-task benchmark, and the results showed that Experts Mode scored 67% higher than its own single-agent mode, leading **Claude Code Agent Teams by 16%**.
Clearly, Qoder's Experts Mode is opening a new stage.
## Ushering in the Era of Multi-Agent Collaborative Programming
After vibe coding and agentic coding, AI Coding is shifting toward the **era of multi-agent collaborative programming**.
Behind this is a change in user needs: they are no longer satisfied with **AI simply writing code**, but hope that **AI can efficiently deliver software, with guaranteed software quality**. A single agent clearly can no longer meet this need, so moving toward multi-agent collaborative programming becomes inevitable.
Multi-agent collaborative programming further amplifies individual capability, giving an individual a digital legion that is on standby at all times, continuously evolving, and understands not just programming but engineering.
This shift also requires the AI IDE to move from simply writing code and organizing files to organizing agents. This also aligns with Karpathy's prediction: in the AI Coding era people still need an IDE, and even need a larger IDE to manage agents. **This is the future direction of the IDE.**

Now, after testing Qoder's Experts Mode, I have already seen the future of AI Coding and the AI IDE in it.
*This article is reprinted from QbitAI | WeChat Official Account QbitAI*
# Pupu Supermarket × Qoder | Enterprise-Grade AI Coding Workshop Wraps Up Successfully
> Pupu Supermarket, together with Alibaba Cloud, held an enterprise-grade AI Coding workshop where 150+ developers put Qoder into hands-on practice.
Pupu Supermarket, in partnership with the Alibaba Cloud Training Center, held an enterprise-grade AI Coding workshop, where 150+ developers jointly explored new practices for landing intelligent programming in the enterprise.

Pupu Technology, together with the Alibaba Cloud Training Center, successfully held a dedicated "Enterprise-Grade AI Coding" workshop. More than 50 core developers gathered in Fuzhou on-site, with 100+ participants joining online simultaneously, together exploring the AI-driven upgrade of enterprise-grade development paradigms.
This training was led by Lyu Zhaobo, a Qoder Ambassador and technical instructor at the Alibaba Cloud Training Center. Aimed at Pupu's Java development team, it covered the full software development lifecycle (SDLC)—from project scanning and requirements design to coding implementation, testing and validation, and deployment and operations. Through Qoder-based Hands-on Lab exercises, it helped participants master enterprise-grade AI Coding best practices.
## Experiment-Driven, with Visible Data
The training deployed a Hands-on Lab Dashboard experiment map on-site, where participants submitted experiment screenshots in groups and the big screen displayed each group's progress in real time. A total of 232 experiment records were generated during the training, with participants' names forming a word cloud scrolling in real time—data-driven, with visible results.
"We already use AI tools like Copilot in our daily work, and this training showed us the complete paradigm of enterprise-grade AI Coding," said one participant. "It's not just about writing code—it's an upgrade of development thinking."
## From Tool Upgrade to Methodology Upgrade

Pupu's development team already had a basic understanding of AI Coding tools, and this training focused on three core upgrade directions:
● **Individual efficiency → team enablement**: Qoder's Skills mechanism makes SOP workflows encapsulable, reusable, and transferable, achieving team-level capability precipitation
● **Code completion → programming prediction**: millisecond-level response, context awareness, and multi-line prediction—moving from passive response to proactive anticipation
● **0-to-1 scenarios → legacy project maintenance**: Repo Wiki lets AI understand historical code, cracking the real enterprise pain point of "taking over legacy projects"
The training also released a four-step path for landing enterprise AI Coding: MCP configuration to connect the foundational tool layer → Rules to inject enterprise coding conventions → Repo Wiki to let AI understand the codebase → Skills to encapsulate and automate SOP workflows, ultimately building an enterprise-exclusive AI Agent that "understands you + understands the codebase + understands history + understands the process."
For this course, we customized **13+** design pattern cards based on the enterprise's current state—such as legacy-project scan mode, Quest delegation mode, and inline prediction—turning abstract AI Coding methodology into reusable, hands-on tools. Participants learned while practicing and mastered the best practices on the spot.
# XPeng Group's First AI Open Competition Concludes, with Qoder Empowering Business Staff to Explore AI Application Innovation
> XPeng Group's first AI Open Competition concludes; a frontline supply-chain employee used Qoder to build the supply-chain risk management platform "Baize" and won the title, boosting risk-screening efficiency 96x
On June 30, 2026, XPeng Group's first AI Open Competition officially came to a close. Launched in May, the competition featured three major tracks and was open to internal employees, employees' family members, and university students nationwide—with no barriers and no professional-background restrictions throughout. It drew more than 21,000 registrations in total, with participating teams including 200 employee-family squads and over 440 university student teams. Qoder, the AI product from Alibaba, served as a key partner of the event, providing technical support and AI capability enablement.

XPeng Group Chairman and CEO He Xiaopeng delivered remarks on site after the competition. He said that XPeng is using AI to drive organizational efficiency, and that AI is no longer exclusive to R\&D but has permeated every role and process—"in the future, AI-driven efficiency gains will gradually move from the hundred-million level to the billion level each year, and even larger." In He Xiaopeng's view, AI should play the role of "amplifying employees" rather than replacing them; the core of technology equality is to dismantle technical barriers, so that "everyone can become a creator and beneficiary of technology."
One noteworthy figure: over 50% of the participants in this competition came from non-technical roles. Procurement, supply chain, finance, marketing, quality—these roles that had never written code before stepped onto XPeng's tech stage for the first time as creators of AI products.
## Business Staff Explore AI Application Innovation with Qoder
Among the most talked-about works at the finals, "Baize," the champion of Track Three "Efficiency Leap," stood out—it was built by a frontline employee from XPeng's supply chain, using Qoder as the creation tool. The author does not come from a traditional technical background but from the supply-chain front line, with a deeper understanding of real business scenarios.

Baize is a complete supply-chain risk management platform. It has 77 built-in risk factors spanning 7 major categories—credit risk, corporate operations, news and public opinion, disaster risk, capacity and delivery, quality, and supporting facilities—while covering 13 primary categories under the two procurement systems of strategic procurement and spot procurement. It comprehensively applies Agent orchestration, large-model reasoning, RAG knowledge enhancement, and time-series forecasting algorithms to achieve 24/7 automated monitoring of full-chain supplier dynamics.
At the risk-governance layer, Baize has handled 100,000+ risk events cumulatively. The platform's built-in risk-disposition generation Agent automatically summarizes events after they occur, distills the core conflicts, provides disposition strategies, and assigns responsible owners. Work that originally required the supply-chain, procurement, and quality teams to coordinate for an entire day can now have AI quickly generate preliminary analysis and disposition recommendations, which business staff then review and refine. At the risk-prediction layer, Baize overlays the EWMA model with large-model AI capabilities to produce a two-dimensional risk-prediction leaderboard across vehicle models and suppliers. After going live, risk-screening efficiency improved 96x, monthly reporting efficiency improved 120x, risk-warning response was shortened to within 5 minutes, and ROI exceeded 35x.
**The Baize project was led and built by XPeng's supply-chain business staff, with Qoder providing AI capability support for some of the business scenarios.**
First, turning business language directly into AI instructions. Supply-chain staff understand best "what counts as an anomaly" and "what kind of supplier needs an alert," and Qoder helps them quickly convert business experience into reusable AI application capabilities. For Baize's automatic identification of news and public-opinion risks, automatic correlation of credit anomalies, and automatic estimation of capacity bottlenecks, staff turned years of accumulated business experience into more efficient application workflows through Qoder.
Second, an end-to-end loop from idea to usable product. Baize has a complete login page, dashboard, model management, data management, event management, Agent disposition reports, and a risk-prediction module—and is currently in use in relevant business scenarios. Qoder provided AI Coding capability support during project development, helping improve business development efficiency and forming a collaboration model of "business poses the problem, AI assists, technology backstops," further shortening the development cycle of business systems.
Third, precipitating enterprise domain knowledge into reusable AI capabilities. Baize's built-in 77 risk factors and 7 major risk templates are essentially the business experience accumulated over many years by XPeng's supply chain—they were structurally precipitated through Qoder and can be further reused across different business scenarios.
## Deep Collaboration Between the Two Parties Covering Full-Stack AI and Global Business
XPeng and Alibaba Cloud have long deepened their collaboration. In the autonomous-driving field, XPeng's second-generation VLA model is trained on Alibaba Cloud's full-stack AI capabilities, with cluster operating efficiency consistently maintained above 90% year-round. XPeng has deployed a foundation model with 72 billion ultra-large-scale parameters in the cloud, with the model completing a full-chain iteration every five days. On the global-business front, Alibaba Cloud's global cloud infrastructure supports XPeng's overseas business expansion, helping XPeng comprehensively improve overseas business deployment efficiency.
From full-stack AI collaboration to global business deployment, and now to the support of Qoder's product lineup for business innovation practices in this AI Open Competition, Alibaba Cloud and XPeng have joined hands comprehensively in the AI field, together opening up an innovation path for AI to move from R\&D to the entire workforce, and from tools to productivity.
# 500,000 Lines of Agent-Written Code Entered Production: What We Got Right
> With Qoder's cognitive foundation, Ultra Spec, and Experts collaboration, a 10-person team safely merged 500,000 lines of Agent-written code into a four-million-line legacy system in three weeks.
Before V1.0 launched, I closed my laptop just as the final group of pull requests had passed every verification step and was ready to merge into the main branch. Every status indicator on the console was green.
By the time we reached v1.4.0, the 500,000 lines written by Agents had been running in production without a single online incident and were still being changed by new requirements every day.
**Delivered and launched in three weeks, 99% generated by Agents, on top of a four-million-line legacy system.**
Writing 500,000 lines in an empty project would not be much of a story. In a greenfield project, an Agent is free to choose the architecture and design the interfaces. No one tells it, "Do not touch that module."
The difficult part was that these 500,000 lines were written with Qoder into Qoder's own codebase. Using our product to build itself put the method and the product on the same lever: the product could work only if the method worked.
## The Eve of Project Kickoff
Our team had already been using Qoder's Agents for everyday coding for nine months. V1.0 needed to answer one question: would this way of working still hold at the scale of adding hundreds of thousands of lines in three weeks?
The night before kickoff, I spread the module-dependency diagrams of two repositories across three monitors: frontend on the left, backend in the center, and knowledge graph on the right. This was not an ordinary iteration touching a few modules. Five hundred thousand new lines had to be laid across four million existing ones. Every possible seam needed to be understood before work began.

From v0.1 last August to today, Qoder expanded to roughly four million lines in nine months. The frontend is a VS Code extension. The backend consists of Go services for Agent orchestration, the knowledge engine, and multi-model invocation, split across two repositories. Iteration was extremely fast. We had experienced small incidents before, and the interfaces carried historical baggage. Repo Wiki and the knowledge graph covered most inter-module dependencies, but some apparently redundant layers had more than ten callers behind them, while the reasons for certain compatibility logic were known only to the people who wrote it. That was manageable when daily work changed only a few modules, but the requirements were different when dozens of Agents were writing in parallel.
We needed to add four major modules: a standalone Quest view, the knowledge engine, multi-workspace parallelism, and Experts collaboration. The launch date was fixed. We had three weeks.
The team consisted of ten people: three on the frontend client extension, four on the Agent harness, and three on the knowledge engine. Every new module required cross-team collaboration.
Under a conventional model, the schedule for this workload would have been several times longer. This major upgrade also gave us a chance to test the real capacity boundary of Agents at this scale.
What happens when the volume rises? How do we ensure that code written simultaneously by dozens of Agents can still run reliably in the existing system?
That was the problem we had to solve over the next three weeks.
## Day Three, and Not a Single Line of Code Yet
By the morning of day three, we still had not asked an Agent to write a single new line of code.
That may sound unreasonable. Why not let the Agents start running and adjust later?
Because those first two days turned out to have the highest return on investment of the entire three weeks. We first refreshed the knowledge layer:
1. **Repo Wiki received a full refresh.** Repo Wiki is a Qoder capability that automatically generates repository-level documentation from code, comments, documents, and commit history without manual intervention. With dozens of Agents about to read the same global view in parallel, we triggered a complete refresh.
2. **The code knowledge graph received a deep update.** This is also a Qoder capability. It automatically models module dependencies, interface contracts, and data flow. We focused on modules added in the previous month and recent interface changes.
3. **Historical Specs and original decisions were added to the repository.** Commit history shows how code changed, but not why a design was chosen. The reasons certain interfaces were deprecated or compatibility layers existed lived only in a few colleagues' memories. We organized that information into documents so Agents could use it too.
Together, we called these three layers the **cognitive foundation**. Dozens of Agents would deliver code autonomously based on the same understanding, so every knowledge gap would be amplified.

Two days and zero lines of code—all spent building the foundation.
On day three, we finally began working on modules. **But we did not begin with code. We began with Specs.**
## "One More Day on the Spec Saves a Week Later"
This was the step with the deepest human involvement and, in retrospect, the highest return.
An ordinary Spec explains what a feature should do. An Ultra Spec is different. Multiple Agents first conduct broad and deep research in parallel so nothing is missed, and then merge and converge the findings into a complete execution plan. Agents work quickly, but people still need to read, challenge, and make trade-offs on every research result. The final Spec must be detailed enough for an Agent to execute directly.
Working in a legacy system adds another perspective: every item must be reviewed from the old system's point of view. Which existing modules will the feature affect? Which old interfaces must remain compatible with the new ones? What unwritten conventions has everyone implicitly followed?
For example, an Ultra Spec for the memory module in the team-shared knowledge engine needed to clarify which conversations would be distilled, when distillation would be triggered, how memories would be stored and retrieved, the interface contract with the existing code-index system, degradation strategies for an oversized memory store, and memory-isolation boundaries between workspaces.
The multi-workspace module was similar. An ordinary Spec might say, "Each workspace maintains an independent Quest session without interference." An Ultra Spec kept asking questions. A scheduled task in the legacy system briefly locks a table—what happens when an overnight Agent attempts a write at the same time? Workspace paths appear in the IDE as directories, `.code-workspace` files, or URIs—which forms does the new code support? Worktree paths are different again—has that been considered? Agents will not think of these questions for you. If they are not raised during the Spec phase, they become a chain of emergency hotfixes after launch.
Writing the Spec was not the end. We started multiple Agents to review the same Spec from different perspectives: an architect examined module boundaries, a security expert looked for permission vulnerabilities, a performance expert anticipated bottlenecks, and a legacy-system expert connected to the knowledge graph checked compatibility. A verifier Agent worked backward to filter out false issues created by Agent hallucinations. People made the final decisions, focusing on SLO definitions and irreversible operations.
Some may think this process is too heavy. Is spending so much effort on a Spec putting the cart before the horse? My experience is that the calculation should be reversed: **one more day on the Spec saves a week later.** Once an Agent starts writing code, correction costs multiply. Anything not clarified in the Spec returns during integration at ten times the cost.
## "More Elegant Than What Our Team Writes"
Once the Ultra Spec was ready, it was time to hand it to Qoder. The knowledge-engine module spanned all three teams: the frontend IDE extension layer, the Go-based Agent orchestration backend, and the core retrieval logic owned by the knowledge-engine team. Nearly ten thousand lines had to change. We knew what would happen if one Agent handled the whole task from beginning to end: in the second half, it would forget earlier agreements. Even though Qoder IDE supports a one-million-token context window, attention dilution and context decay still occur as context grows. A larger window does not mean every token receives equal attention.
So we started **Experts Mode**.
A Team Lead expert does not write code. It reads the Ultra Spec's task list, identifies dependencies, breaks the work into a DAG, and delegates subtasks. Tasks with dependencies do not run in parallel, and tasks likely to edit the same file do not run simultaneously. Backend, frontend, testing, and review experts each take their own assignments in independent contexts.
That afternoon, I opened the Quest task board and watched 11 different Experts tasks progress at once. Within each task, a frontend expert built the memory-display component, a backend expert implemented storage and retrieval interfaces, a testing expert generated regression cases from the Spec, and a research expert scanned the legacy modules for compatibility boundaries. Every expert operated in its own independent context.
In the previous single-Agent mode, every choice—solution A or B, which encryption algorithm to use—could stop the Agent and require a person. With a Team Lead coordinating the whole task, it made many intermediate decisions directly and surfaced only irreversible choices as question cards for human judgment. I was barely interrupted that afternoon.
**But speed was not the key, although it was genuinely fast.**
The code written by the 11 experts in that module shared consistent style, naming, and layering. The same held globally: multiple Experts tasks ran in each of the four modules, yet cross-module code still followed team conventions. That consistency came from the newly refreshed shared knowledge engine and the same original decision records.
A colleague looked over at my screen and said, "It is more elegant than what our team writes."
## Thousands of Subtasks, Ten People
**The greatest change produced by this model was execution efficiency and judgment.**
A single Agent might take a long time to run the same task and repeatedly stop to ask people questions. With Experts, parallelizable work runs in parallel, the Team Lead handles many intermediate decisions, and people confirm only key nodes. Ten colleagues formed three groups, each running Experts tasks for its own modules. The groups aligned boundaries through the knowledge graph and Ultra Spec. Over the three weeks, they ran thousands of subtasks—roughly, each person led more than 20 Experts tasks per day, and every expert split work further in parallel. Overall execution efficiency was an order of magnitude higher than single-Agent mode.
We gained something else too. Qoder's memory system developed a genuine flywheel under this intensive use. After an expert Agent completes a run, experience is automatically accumulated as an Expert Skill—for example, how to start a module's test environment or which historical pitfalls an interface contains. Key decisions enter the knowledge engine, while obsolete information is automatically forgotten or replaced. The effect became increasingly visible over the three weeks.
## Three Weeks Later
At the end of the third week, all 500,000 new lines had entered the main branch. The standalone Quest view, knowledge engine, multi-workspace parallelism, and Experts collaboration were integrated into Qoder V1.0.
All four modules were ready the night before delivery. Ten people, three weeks, 500,000 lines: that was the capacity produced by this method.
People participated most deeply in writing the Ultra Spec at the beginning. While Agents wrote code in parallel, each group moved on to its next high-value work. The frontend group prepared interaction sketches for the next module. The Agent group handled cross-module decisions escalated by Team Leads. The knowledge-engine group worked with research Agents to calibrate legacy boundaries.
In *The Mythical Man-Month*, Brooks wrote that adding people to a late project only makes it later. Teams are actively practicing the alternative—adding Agents instead of people—but succeeding in production requires more than having a Coding Agent. Agents need to run in the right environment and system, under constraints and conventions, with problems traceable when they occur. Without that foundation, adding Agents resembles adding people, and delivery lead time does not shrink.
When we reviewed V1.0, these were the things we got right:
- **Cognitive foundation** (Repo Wiki + code knowledge graph + historical Specs): enabled Agents to understand the current state and history of the legacy code without repeatedly realigning context.
- **Ultra Spec** (divergent-then-convergent Specs + cross-review by multiple Agents): exposed ambiguity and rework risk before implementation, avoiding mutually destructive changes during integration.
- **Experts collaboration** (Team Lead + specialized Agents in parallel): divided large tasks into parallelizable subtasks rather than leaving everything on a single thread.
Together, these three parts solved the question I had asked on the first day: could 500,000 lines written by Agents be maintained and continuously iterated within a four-million-line legacy system, without becoming a black box no one dared to touch?
Today, the answer is: **there have been no production incidents since launch, and the code is still being changed by new requirements every day.**
## The Story Is Not Over
That concludes the first part.
But you may have noticed a missing step. I skipped the journey from 500,000 lines written by Agents on branches to production. After Ultra Spec set the direction and Experts delivered the code, one guardrail still stood between the code and a safe merge and release.
That guardrail had two parts: Ultra Review before merge, and Computer Use + Nightly Auto-Heal after merge, when people leave work and machines take over. Agent-generated code appears far faster than people can review it. Ultra Review uses multiple Agents in parallel to match code-generation speed. Computer Use + Nightly Auto-Heal lets machines run the discover-fix-verify loop themselves, moving people out of the bug pipeline.

Together, we call these capabilities **Autonomous Engineering**. The method changes from people directing multiple Agents to machines running the loop themselves.
[Contact us for more enterprise solutions ➔](https://page.aliyun.com/form/act465803565/index.htm?spm=a2c7g.act_detail.main.6.21921b90ToNJto)
# I Used Qoder Experts to Assemble an AI Team—30-Minute Delivery, Promoted Tomorrow
> Making good use of Qoder Experts Mode to assemble a multi-Agent expert team, delivering merge-to-main features through 30-minute parallel work.
I'm a bit of a perfectionist—the moment I see a software update prompt, I upgrade right away.
Sure enough, after upgrading Qoder to the latest V0.8, the Experts Mode I'd been waiting for finally went live!
Much like the Team Agent in Claude Code, Qoder's Experts Mode also evolves AI from a single Agent to multi-Agent collaboration.
The Leader Agent is responsible for breaking down tasks, assembling the team, and tracking progress, while the Frontend Dev, Backend Dev, and QA Tester work in parallel—you only need to review the plan and accept the results.
I recorded a screen capture so everyone can get a feel for it in advance.
> This whole piece is intense—buckle up, we're hitting the road. Beep beep, off we go.
## 01. What Is Experts Mode?
Each expert in Experts Mode is a specially tuned SWE Agent (Software Engineering Agent).
This so-called specialized tuning isn't merely swapping in a different prompt; it involves targeted optimization across model selection, parameter configuration, context management, tool calling, and more.
For those who haven't downloaded it yet, copy this address and open it in your browser.
> [https://qoder.com/ide](https://qoder.com/ide)
After installing, open Qoder, create a new session, select \[Experts Team], switch to Experts Mode, and then enter your requirements to get started.
We just provide the requirements, and the Leader Agent automatically assembles a team of experts who work in parallel—well-suited for complex, multi-step tasks.
In this mode, the AI is an engineering team and you're the project manager, responsible for reviewing the plan and accepting the results.
More importantly, different experts are automatically routed to the model best suited for them.
The Leader Agent needs to do complex task planning and decision-making, so it might route to Opus, which has the strongest reasoning ability; the Backend Dev needs to write high-quality Java code, so it might route to GLM5, which excels at coding; the QA Tester needs to do browser automation testing, so it might route to Kimi K2.5, which supports vision capabilities.
In plain terms: you give the requirements, and Experts Mode assembles a team to do the work for you.
The Agent workhorse squad has arrived.
As everyone knows, in real-world software development, a complex feature is never written by one person from start to finish. Instead, an architect or tech Leader does the design first, then splits it among different roles—frontend, backend, testing—for parallel development, and finally integration testing.
Experts Mode is exactly this collaboration model.
## 02. Experts Mode in Action
Talk is cheap—let's get straight to practice.
### A First Try
I happen to have a PaiGit project on hand—a source-code management platform similar to GitCode, GitHub, and Gitee. Its current features include repository import, Issue management, Wiki generation, and more.
> Prompt: Start the frontend and backend separately; let's first take a look at the current development progress.
In the past, we'd need to start the backend in IntelliJ IDEA, then start the frontend with a separate frontend IDE, and then open the browser to visit the address.
Right?
And now?
Qoder proactively brings up the frontend and backend for us, then assigns a test engineer, Alex, to help us check the project's development progress.
He automatically opens the browser (note the Chrome in the top-left corner being controlled by automated testing software) and then verifies each feature one by one for us.
And gives us a final report: the authentication module (fully implemented), the home browsing module (fully implemented), the repository details module (fully implemented), and the user dashboard (fully implemented).
Afterward, it even thoughtfully asks whether we want to generate the project's Wiki. Of course we do.
### Going All Out
Since Qoder told us there are still three directions to improve—Issue creation/editing/commenting, Wiki page creation/editing, and refining the download feature—
we launch all three features in parallel right away.
At this point, Experts Mode pulls the investigator Sam (Research Agent) into the Team, responsible for investigating the existing code state of the three modules, then formulating specific tasks for parallel development.
Heh, this really is comfortable.
Throughout the whole process, it felt like I didn't even have to use my brain—Qoder thought of everything for me.
OK, after a short wait, the tasks are ready.
Experts Mode pulls backend engineer Jimmy into the Team, responsible for Task 1: Issue module enhancement—editing issues and editing/deleting comments.
Maybe Experts Mode felt one backend engineer was too slow, so it pulled in Bill too, responsible for Task 2: Wiki module enhancement—manually creating/editing/deleting Wiki pages.
That's not all.
Experts Mode then pulled in frontend engineer Robin as well, responsible for the frontend refinement of the download module: the admin review panel and the user download experience.
Wow, a true Agent legion.
Three experts working at the same time, without interfering with one another. I could see each expert's progress in real time on the interface. The efficiency of this parallel work is clearly higher than a single Agent executing serially.
At this moment, I no longer knew whether I was living in a real-world team or in a cyberpunk future.
I believe everyone here is a loyal fan of IntelliJ IDEA, but at this moment, I already felt a slight worry.
AI IDEs are evolving way too fast.
You can't help but marvel at Qoder's speed of evolution.
After the development tasks were done, Experts Mode pulled in a new test engineer, Chris, responsible for verifying whether these three features were complete.
Soon, the test results came in too.
Issue editing and comment management — fully working. An "Edit" button was added to the top-right of the Issue detail page, supporting inline editing of the title and content. Each comment in the comments section has "Edit" and "Delete" links next to it (visible only to the author/admin), and deletion has a confirmation dialog to prevent accidental actions.
Wiki creation/editing/deletion — fully working. The Wiki page added a "New Page" entry, and the creation form supports title + Markdown content input. Existing pages show an "Edit" button, and admins additionally see a red "Delete" button. Markdown renders well, with titles, lists, code blocks, and links all displaying correctly.
Download module frontend refinement — working properly. The Dashboard added a "My Download Requests" section, showing request history and status tags (Approved/green). The admin area retained the "Pending Download Requests" panel, supporting approve/reject actions. The download button on the repository details page displays correctly according to status.
As an old-timer programmer, seeing the results at this moment, I felt both delighted and astonished.
The delight: Qoder's progress along the way is truly there for all to see. From now on, when I develop projects for everyone, all that's left is to burn tokens.
The astonishment: after not looking for just a few days, Qoder has evolved to this point—completely exceeding my initial expectations for Experts Mode.
Test engineer Chris even kept some of her testing evidence; click the image to view it.
In this round of development, a total of 19 code files were modified—truly impressive.
### Verifying the Results
Let's manually verify the results. For the Issue part here, confirmed no problems.
Indeed, everything's fine.
This kind of autonomous coordination among experts saved me a lot of communication overhead. In a traditional development process, this kind of frontend-backend format inconsistency would require manual intervention to coordinate.
But in Experts Mode, the experts discovered the problem themselves, discussed the solution themselves, and only needed me to confirm at the key decision points.
Overall, the delivery quality was quite good—reaching a standard that could be merged directly into the main branch.
## 03. The Advantages of Experts Mode
Unlike a traditional single Agent, the advantages of Experts Mode are quite obvious.
① Planning first makes the overall architecture clearer. The Leader Agent produces a complete plan first; I review and confirm it before execution, so it's less likely to go off track. Even if there are adjustments during execution, they're adjustments within the overall framework and won't stray too far.
② Multiple experts work simultaneously—the Backend Dev writes the backend while the Frontend Dev writes the frontend, the Researcher does research, and the QA Tester prepares test cases. This level of parallelism is something a single Agent can't match.
There's one thing I especially appreciate: every time a new feature is developed, the investigator steps in to ensure that all development tasks are crystal clear.
This reduces a lot of rework.
In the real world, development often outpaces requirements research, leading to later rework until the development matches what was wanted.
Because sometimes even the client can't figure out their own requirements. But in Experts Mode, you can clearly feel that specialized division of labor guarantees quality. Each works deeply and thoroughly in their own domain. There's no situation of "knowing a bit of everything but mastering nothing."
## 04. How to Get Experts Mode
Currently, there are several tiers for getting Experts Mode.
Pro+, Ultra, and Teams users unlock it upon subscription—no application needed; just switch to Experts in the mode selector to use it.
Well, I'm Pro+ (let me splurge 😄).
Pro users can join the Waitlist for priority review, and will be notified by email once approved.
> [https://qoder.com/ide?waitlist](https://qoder.com/ide?waitlist)
By the way, new users who register for Qoder get a 14-day free Pro Trial and an extra 300 Credits.
My usage suggestion: first use Agent Mode to get familiar with Qoder's basic operations, then upgrade to Experts Mode when you hit complex tasks. Don't jump straight into Experts Mode for simple tasks—that's a bit of overkill.
## Ending
After heavily using Experts Mode for a while, I have one strong feeling: AI programming tools are evolving from "pair programming" to "engineering delivery."
AI programming in the past meant AI assisting you in writing code. You were still the protagonist, and AI was the assistant. You had to tell the AI what to do at every step, check every line of code the AI wrote, and correct every mistake the AI made.
Today's Experts Mode is an AI team delivering features for you. You've become the project manager, and the AI is the execution team. You're responsible for defining the problem, reviewing the plan, and making decisions; the AI is responsible for the concrete implementation, quality assurance, and progress tracking. In this mode, the AI is a team and you're a manager.
The significance of this shift is profound.
I hereby declare that Qoder Experts Mode will be the main force for my complex tasks from now on.
This mode is just too good to use—oh my goodness.
You can manage multiple tasks at the same time. Before, for a complex feature, you had to keep your full attention on the AI and couldn't do anything else. Now you toss the requirements to Experts Mode, go do something else, and just wait for the notification to accept the results. Your time is freed up to handle higher-level problems.
Your role is being upgraded—from "the person who writes code" to "the person who defines problems, reviews plans, and makes decisions." This is exactly the direction programmers should evolve in the AI era. When AI can write code, a person's value lies not in the speed of writing code, but in understanding the business, controlling the architecture, and holding the line on quality.
**\[The future of software development may truly be a model of "one person + one AI team." One person can manage multiple AI experts and complete tasks that previously required a whole team.]**
This isn't the future—it's what's happening right now.
# On My Favorite Qoder Features and Tips for Saving Credits
> Making good use of Qoder's five core capabilities to boost efficiency, with six hands-on tips for saving Credits.
Hi everyone, I'm Ren Fu, a technical developer from Cainiao Cross-Border Logistics. Today I'm honored to share, from a user-experience perspective, a best practice on how our team and I have used Qoder to boost R\&D efficiency.
## The Evolution of AI Programming
We actually started exploring AI programming last year, or even earlier. Along the way, we tried a number of different AI programming tools, including but not limited to Aone Copilot, Suite Copilot, GitHub Copilot, and Claude Code, among other mainstream tools.
Over the past year, AI programming tools underwent a rapid shift: from initial code-assistance tools, they gradually evolved into more intelligent and autonomous Agentic programming tools. Alongside this upgrade, the R\&D paradigm of AI Coding has been evolving too. We moved from the earliest Vibe Coding—producing the desired effect through natural-language input—and gradually shifted to the Spec Coding model, which produces high-quality, production-grade code through defined specification constraints.
The core logic here is that we no longer intervene only after problems surface in the software engineering code; instead, we constrain things through specifications—including architecture design and more—solidifying the entire development process first, and generating higher-quality production code under clear constraints.
But over the past year-plus of practice, we also found that these tools generally share some problems:
- **Free improvisation**: Due to a lack of clear planning and description, agents hallucinate when understanding the business and generating code.
- **Low efficiency**: The generated code isn't sufficient to be produced against complex business contexts. Developers lack well-designed instructions and standard constraints, so the AI can't clearly understand the requirements and fails to form effective solution designs and task breakdowns.
- **Loss of key information**: Limited by the context length of past large models, multi-round interactions with AI accumulate a lot of information, causing the AI's comprehension to decline.
As model capabilities have improved dramatically, these problems have now been alleviated. I started trying Qoder in October last year and found its capabilities more than enough to solve the issues above.
## Qoder's Core Capabilities and Systematic Approach
### Qoder's Five Core Capabilities
#### 01 Core Capability 1: Repo Wiki
This is my personal favorite feature. With a single click on the icon, it generates a detailed description of the current project, covering the project overview, technical architecture, development guide, deployment guide, and development standards—even including sequence diagrams and flowcharts. For those unfamiliar with the system, this helps them integrate into development quickly. In addition, it supports dynamic refresh, iterating based on Git code changes.
#### 02 Core Capability 2: Rules
Large models rely on general knowledge and lack specific contextual background. Through the Rules feature, Qoder lets you configure predefined context and R\&D coding standards (such as code-quality preferences) into a directory. You can write them by hand, or find best practices from open-source sites and drop them in. You can even have Qoder proactively generate rules for you during development (such as unit-test rules).
#### 03 Core Capability 3: Memory
During multi-round interactions, Qoder can generate a memory list based on communication style and personal preferences (such as user identity, area of expertise, commonly used tech stack, and environment configuration), and continuously load it in subsequent conversations.
#### 04 Core Capability 4: MCP
This mainly solves the connection-protocol problem when integrating an LLM with external data sources and external tools. We can register browser capabilities, drawing tools, or MCP services from other systems here, and Qoder will autonomously choose the tool as needed during interactions.
#### 05 Core Capability 5: Skills
This can be understood as a modular, reusable SOP workflow with domain-specific knowledge. It's stored in the .qoder/skills directory and teaches Qoder how to complete specific tasks.
### Comparing Qoder Quest Mode and Agent Mode
- **Quest mode**: This is a Spec-driven form of autonomous programming. Based on the user's requirement input, it generates a structured requirements document, architecture design, and a To-do List. Once we confirm, the remaining tasks are handed off entirely to the AI to complete end-to-end delivery autonomously.
- **Agent mode**: This is the mode we use more often in day-to-day development. You enter requirements in the dialog box, and the AI performs intent recognition and generates an execution plan. It loads Repo Wiki, Rules, Memory, and more into the context to understand and output code.
Compared with Quest mode, Agent mode lets us terminate and correct in a timely manner during the exchange. Meanwhile, beyond its four built-in model tiers, Agent mode has also recently added support for bringing in other large models via an Alibaba Cloud subscription.
## Practical Cases in Daily Work
### Case 1: Building a Local Video Player from 0 to 1
As a developer—or someone who doesn't know how to code—if you want to implement a feature from 0 to 1, you can follow the flow of "requirements -> architecture design -> development and testing":
- **Requirements phase**: Use prompts to specify the role, content, and deliverables, and output a product PRD document.
- **Architecture design phase**: Bring the PRD into the context and have Qoder design the Spec specification and To-do items in conjunction with the PRD.
- **Development and testing phase**: After reviewing the specification (including technology selection, risks, and architecture), enter the code-generation phase. If there are issues with the feature implementation, make corrections.
### Case 2: Adding a Report Menu
Leveraging Repo Wiki's code-mapping capability, first discuss the approach with Qoder. Through prompt engineering (specifying the role, goal, and reference cases), have Qoder enter the Plan phase. It analyzes the current architecture and proposes a solution design. Finally, you select the solution you're satisfied with, generate the to-dos, and move into development.
## Best Practices for Saving Credits
As a developer, while enjoying an efficient experience, you should also pay attention to saving costs. I've summarized six best practices:
1. **Start a new window for unrelated topics**: If you find that faulty input has caused context redundancy, or Qoder has misunderstood something or the topic is unrelated, terminate promptly to avoid wasting tokens.
2. **Choose the model tier as needed**: Use lightweight mode for simple requirements, and only use Auto or the ultimate mode for complex features, to balance cost and results.
3. **Optimize the code repository structure**: Reduce ineffective output. Qoder sometimes produces unit tests or MD documentation explanations by default; if you don't need them, explicitly exclude them in your instructions.
4. **Make expected behavior explicit**: Use configuration to exclude irrelevant directories, preventing them from being loaded into the context.
5. **Terminate immediately when it goes off track**: During interactions, if insufficient business-context input leads to wrong results, terminate promptly to avoid Qoder over-diverging.
6. **Roll back in an engineered way**: One approach is to use a positive example to have Qoder correct its previous round of output; another is to directly roll back the version via Git and regenerate.
### 1) The R\&D Paradigm Shifts, and Interaction Changes
Over the past year-plus of AI programming practice, we've evolved from "old-school programming" to assisted programming, and now to Agentic autonomous programming. This is not just an upgrade in tool capabilities, but a shift in the R\&D paradigm—from simply trying out effects to a Spec Coding model that can truly reach production.
With the emergence of MCP and Skills capabilities, future system design or interface design needs to focus more on how to make things more general and more reusable, so that AI can integrate better into the ecosystem.
### 2) Observability and Security Review Become Key Focuses
As AI enters the production grade, code accountability becomes critical. We need observability, traceability, and security-review capabilities for AI-generated code to protect enterprises' sensitive data and hold the security line.
### 3) The Application Marketplace Diversifies, Beyond Just Coding
Recently I've also been trying QoderWork. It has actually already brought in various capabilities—browsers, software systems, and more—through MCP or built-in skills. When you need to produce a document or file, you just describe the requirement, and it can collaborate with you to produce it like a colleague.
Right now, AI Coding is no longer just about coding. From a technical standpoint, it's shifting from development to broader usage scenarios for more people, such as business and operations. In the future, we won't just embrace AI—we'll actively welcome the wave of AI.
I look forward to Qoder driving an even greater leap in R\&D productivity. Let's build a smarter future together.
# I Can't Code, but I Built an iOS App
> A non-technical operations person made good use of Qoder to build a personal iOS movie app in a single day.
Coming home from work one evening, I wanted to watch a movie. I opened one video app after another, and faced with the overwhelming lists of recommendations, I actually had no idea what to watch. After scrolling on the couch for twenty minutes, I ended up watching nothing and just went to sleep.
I do operations on the Qoder team, and I can't code. But I had an idea: could I make an app that just recommends a few movies to me every day, so I can swipe through and decide what to watch tonight? Swipe away what I don't like, save what I do. No "recommended for you" algorithms, no community—just five movies a day, deciding by the posters.
Inspired by my colleagues, after lunch one day I decided to stop just thinking about it. I opened Qoder and dove right in.
What happened next surprised me. I did actually build it—an iOS app called "Daily Movie" that runs on an iPhone with a pretty decent experience. But the process was far from as smooth as I'd imagined: environment setup cost me two hours, the share feature caused the app to crash outright, and the UI, once built, obviously "looked AI-made." Later, scrolling through social media, I saw a popular analogy: thinking Vibe Coding will make you money is like buying a coffee machine and assuming you can open a café. I found it quite apt. Letting AI work purely on vibes can get you started, but it won't take you far. What eventually filled in the gaps for me was describing my requirements more clearly, and loading professional standards onto the Agent (both Qoder and the industry call these Skills—more on that later).
## From Idea to a Running App
### 01. Building the App Framework with Quest Mode
I opened Qoder and selected Quest mode from the top-left corner.

Once inside, there are three templates to choose from:
- Spec-Driven (Code with Spec): suited for development tasks with clear requirements and a defined plan
- Prototype Demos: suited for quickly turning an idea into a previewable prototype
- Create Tools: suited for building tool-type applications

What I wanted to build was an app prototype, so I chose Prototype Demos.
The way these three templates are divided is worth mentioning. Prototype Demos suits "I have an idea, let's get it running and see"—essentially structured Vibe Coding: you describe a vague goal, and the Agent helps you explore quickly. Code with Spec takes another path: first write clearly what you want and what the acceptance criteria are, then the Agent executes according to the Spec. One goes from vague to clear; the other from clear to done. As I'll get to later, I started with Prototype Demos this time, but what really kept the project from spinning out of control was exactly the "Spec-style thinking" I gradually learned along the way.
There's an easy pitfall when collaborating with an Agent: the more you try to control every step, the more easily it goes astray. A better approach is to **describe the destination, not dictate the route**. A developer on my team put it well: clarify the intent, and the Spec will grow out naturally. So instead of saying "first create a React Native project, then configure the navigation routes...", I poured out the whole concept of "Daily Movie" and the features I wanted all at once: recommend 5 movies a day, support swiping up and down, allow saving favorites, and give it a cinema feel. The more specific the intent, the higher the completeness of the Agent's first version. Qoder Quest 1.0 responded quickly and gave me two options: one to run inside QStudio, and another to generate a standalone React Native project. Without much hesitation, I chose the second.

Before long, Quest had scaffolded the app prototype and told me where the project was located.
Then came the problem: how do I set up the runtime environment?
I grilled Quest with question after question. This step took about two hours, mainly getting stuck in two places: first, the wrong Node.js version meant dependencies wouldn't install; second, the iOS simulator needed to be downloaded separately, and the operations in Xcode were complete gibberish to me. At one point I stared at Xcode's enormous interface—full of buttons and menus I didn't recognize—and really wanted to just shut down the computer. Luckily, every time I hit an error I just screenshotted it and threw it at Qoder, and it could always help me pinpoint the cause and give a solution.
Ironically, the "writing code" part was something Qoder handled in minutes; what really gave me trouble was everything outside the code: how to install the iOS simulator, those cryptic options in Xcode, and so on. The Agent can help you write code, but for these environment and tooling problems, Quest can only give you suggestions—the final call is still up to you.
In the end, I successfully launched "Daily Movie" on the iOS simulator using Expo Go.

When the app ran for the first time, I froze for a few seconds, then took a screenshot and sent it to the work group chat. A colleague replied, "You made this?" and I said, "Strictly speaking, Quest made it, but the idea was mine." Even though it was still using mock data, both the main screen and the detail page were there, and the overall framework already looked the part.
### 02. Connecting Real Movie Data
Fake data is ultimately fake; it had to be swapped for real movie information. But where would the data come from?
I asked Qoder to recommend a suitable data source, and it suggested TMDb (The Movie Database), which offers a free movie data API. You can get information on millions of movies worldwide, it's usable right after registration, and it's perfect for personal projects. I followed the process to register an account, applied for developer access, and after getting the API Key I told Qoder to do the integration—and got the real data quite smoothly.
Opening the app and seeing real movie posters load one after another, it instantly felt "alive."

### 03. Killing the "AI Flavor" with Skills
With the data in place, the next step was designing the UI.
I told Qoder I wanted that dark-cinema feel: the movie cards should be big, with the poster as the star. Because the core of this app is deciding by the poster, if you can't see the poster clearly the whole experience falls apart. After tapping a card, you should see the full movie info—rating, director, cast, and synopsis—plus a favorite button and a link to the TMDb web page.
For the UI design, I went through three or four rounds of adjustments:
- The first version's cards were too small and the posters unclear → "Make the cards taller, taking up 2/3 of the screen height"
- The rating numbers were too small → "Make the rating numbers one size bigger and bold"
- The transition between the bottom text and the poster was too abrupt → "Add a gradient at the bottom of the poster, from transparent to black"
After three rounds it still felt slightly off—I couldn't say exactly what was wrong, but there was a certain "AI flavor." The layout was fine, but the details lacked a sense of design.
A lot of people probably relate to this feeling. AI-generated UIs often have spacing so even it feels mechanical, and color combinations that are technically correct but lack rhythm—like a dish cooked strictly by the recipe, with every gram of seasoning right, but missing that "wok breath." Y Combinator founder Paul Graham has a point: when you can't provide decoration, you must provide substance. AI is exactly the opposite—it can give you any decoration, but what it lacks is judgment, like whether this spacing should be 12px or 16px, whether this text should be bold or grayed out. Between "usable" and "wanting to use it," what's missing is exactly this layer of taste.
AI itself has no taste, but you can load taste onto it. Some say giving AI taste could be the next transformer-level breakthrough. I don't know whether that's true, but at least in my project, the boost from installing "taste" onto the AI (namely, Skills) was greater than having it write ten more rounds of code.
That's when I thought of trying Skills. Simply put, it means loading a domain-specific professional knowledge pack onto Qoder. I installed a Skill called `frontend-design`, then had Qoder re-optimize the UI according to the design standards inside it.
Here's a small tip worth sharing: after installing a Skill, write your instructions specifically.
The Skill gives the AI concrete design standards; the more precise your instructions, the more reliable the output.
But honestly, at the time I didn't think that much—I just felt: after installing the Skill, the results were so much better. What makes a Skill different from an ordinary document is that it isn't written once and then left to gather dust; it's a "living standard" the AI reads every time it works. It takes effect each time it's used, and there's no problem of it becoming outdated.

The difference was quite obvious. The earlier UI was like "usable," while the UI after adding the Skill was like "wanting to use it." The cards' rounded corners, font hierarchy, and spacing rhythm all felt more comfortable—no longer that cookie-cutter AI aesthetic.
Just like that, Quest handled the scaffolding and implementation, Skills handled quality control, and the final result genuinely surprised me.


### 04. The Favorites Feature
The requirement for this feature was straightforward: "I want to save movies I like into a favorites list, and still see them the next time I open the app. Favorites is a separate page that displays all the movies I've saved."
Quest used something called AsyncStorage, which you can simply think of as a "little warehouse" on the phone's local storage. The favorited movie data is stored in this warehouse; close the app and reopen it and it's still there, viewable without an internet connection. This feature went smoothly, with no pitfalls.

### 05. Pitfalls in the Share Feature
This step hit a big pitfall. Initially I told Qoder: "I want to make a beautiful image share card with the movie poster and a QR code, so users can save the image and share it." Qoder quickly implemented a solution for me: use react-native-view-shot to take a screenshot, and expo-sharing to share.
But once installed, the app crashed outright. It was the kind of crash where you tap once, the screen goes black, and you're bounced back to the home screen—clean and decisive, no struggle at all.
I threw the error message at Qoder, and after analyzing it, it told me: the native modules these features depend on can't run in the Expo Go environment; you need to build a standalone version of the app. And building a standalone version meant dealing with an Apple Developer account, signing certificates, and the like—too complicated for me.
I wasn't ready to give up, so I tried two or three alternative approaches, each with its own problems. After going back and forth for over two hours, I was honestly quite frustrated, because the share card was a feature I'd especially wanted from the start. But in the end I accepted it and simplified the plan: switch to plain text content plus React Native's native share component.
The final share content looked like this:

No fancy card, but usable and stable.
The biggest lesson this taught me: build a running version first, and keep iterating on the complex stuff later.
AI is indeed efficient on the "standard path," but when it hits platform boundaries (Expo Go's native module limits, Apple Developer's certificate system, etc.), it can only tell you where the problem is—it can't decide for you what to do. What finally pulled me out of the pit was one word: cut. I cut the image share card and switched to plain text, saving the time to polish the features that really mattered. Honestly, I was reluctant when cutting it, but looking back the decision was right—otherwise I'd have been stuck there.
### 06. Detail Polishing and Performance Optimization
After the basic features were done, I spent more time polishing details with Quest:
- **The "Not Interested" button**: Don't want to watch one of the 5 movies recommended today? Tap "Not for me" to swap in another. But you can only swap 3 times a day; once you're out, it prompts "Come back tomorrow." This design is intentional—if you could swap infinitely, the recommendations would turn into a random shuffle player, and the ritual feel of a "daily selection" would be gone. Also, appropriately limiting options actually helps you decide faster. Against decision paralysis, sometimes less is more.
- **Daily refresh logic**: The five movies refresh based on UTC+8—that is, they update at midnight Beijing time. I discovered this bug through my own use: opening it at 1 a.m. still showed yesterday's lineup, and I thought the algorithm was broken. It took a while to troubleshoot before I realized it was a time zone issue. My operations instincts finally came in handy.
- **Haptic feedback**: When swiping to switch, tapping buttons, or favoriting a movie, the phone gives a slight vibration feedback. After adding this, the experience improved noticeably, and the tactile feel came close to a native iPhone app.
After tuning the feature details, I found a problem: the app would occasionally stutter a little when quickly swiping between movie cards, and poster image loading wasn't smooth enough. That's when I remembered my earlier experience installing `frontend-design`, so I searched through Skills and found one called `vercel-react-native-skills`—a collection of React Native and Expo best practices from the Vercel team, dedicated to solving mobile performance issues.
After installing it, I told Qoder: "Referencing the `vercel-react-native-skills` standards, optimize the swiping performance of the movie card list and the poster image loading."

Following the rules in this Skill, Quest made a whole set of optimizations: poster images switched to a more efficient loading method, so when you open the app it first shows a blurred color block and then smoothly transitions to the high-definition image, with no white-screen flicker; the large background images were intelligently compressed, shrinking to a fraction of the size while looking no different in quality on the phone; and the underlying logic of the scrolling list was cleaned up, so content scrolled past automatically releases memory, and it won't get laggier the more you scroll. I have no idea how any of this works under the hood, but the results are real—after the optimization, swiping on a real device was noticeably smoother than before, and poster images appeared almost instantly.
`frontend-design` made the UI no longer look like an AI template, and `vercel-react-native-skills` made the swiping and loading keep up with the speed of your hand. With the two Skills working together, the app's quality genuinely leveled up.
### 07. Some Thoughts After Finishing
On social media, I found many people discussing similar things. Some say Vibe Coding will soon hit a wall—once a project gets big it starts to "drift," and the Agent, changing things bit by bit, can't even clearly say what it changed. Others say only SDD (Spec-Driven Development) is the GOAT: write the requirements and architecture docs clearly first, then let the Agent get to work. Looking back, isn't that exactly my journey? At first, letting AI work purely on vibes was indeed fast, but I got stuck on things like environment setup, platform limits, and design quality. Later I gradually learned to describe requirements more specifically and then loaded Skills onto the Agent, and only then did the results come through.
There's also a particularly funny one: the product manager says with AI you don't have to wait for the designer's mockups; the designer says with AI you don't have to wait for the developer to write code; the developer says with AI you don't have to wait for the PM to write requirements. After reading that I thought: so as an operations person, have I just bypassed all three of them? After all, users having needs and feedback is eternal.
Another line that resonated with me: "If the Agent can write code, it can also update the plan. Just let it do it." Skills go a step further—the Agent doesn't have to guess what a good SOP is; it just reads the standard and follows it.
I now lean toward thinking that Vibe Coding is a great starting point, but it can't carry you the whole way on its own. If I had started with Code with Spec back then—spending 10 minutes to write the requirements and acceptance criteria clearly—I probably wouldn't have hit that share-feature pitfall at all. Of course, without that initial "let me just try it" impulse, I might still be just thinking about it. So you need both; it's just a matter of order and proportion.
Karpathy says future software will become highly personalized: everyone will have AI generate an app on the spot for their own needs, use it and toss it, without downloading someone else's generic product from the App Store. He calls this "bespoke software," and made an analogy: today's software is like a castle built from bricks, while future software is more like a pot of boiling soup—code cooked up as needed, and gone once you've drunk it.

The moment I saw it, I thought: isn't this describing "Daily Movie"? Five movies a day, swipe up and down, decide by the poster—this kind of need is so specific that no one in the App Store would ever build one that perfectly fits my taste. But I built it in a single day, and even though it's just for myself, the experience suits me far better than those "big and comprehensive" movie apps.
That said, looking back after finishing, there's something rather ironic: what took me the most time wasn't "building" it, but "turning it into an iOS app." Qoder wrote the code quickly, and the rest of the time was all spent wrestling with the iOS ecosystem: Xcode, the simulator, Expo Go's native module limits, Apple Developer certificates. It's 2026, and 99% of services still don't have AI-friendly interfaces—users still have to operate web pages by hand. "What am I, a computer?" I deeply relate; that's exactly how I felt staring at Xcode.
If, as Karpathy says, future software doesn't need to be an app, doesn't need the App Store, doesn't need signing certificates, and code is generated on demand and gone after use—then half the pitfalls in this article simply wouldn't exist. But we're not there yet; we're stuck in a transition period: AI's ability to write code has arrived, but the infrastructure to actually run that code is still the old way. Still, for people with specific needs who are willing to tinker, the barrier really is much lower than before—and it's dropping fast.
### 08. The Final Result
At this point, the development of "Daily Movie" reached a milestone. I installed Expo Go on a real iPhone, scanned the code to run it, and the overall experience was much better than I'd expected—smooth swiping, silky interactions.
To sum up the experience of the final version of the app:
- Ready to use right away, no registration or login needed
- 5 hand-picked TMDb-rated (6+) movies a day, browsed by swiping up and down
- Tap to view details, favorite and share in one tap
- Enhanced with haptic feedback, with a tactile feel close to native
Next, I plan to keep figuring out how to properly package and install the app onto my own iPhone, break free from Expo Go, and truly "own" this app of my own. That pitfall—I'll write about it once I've been through it.
### 09. A Few Tips for Friends Who Want to Build Apps with AI
1. **Pick the right template first**: If you want to validate an idea or make a presentable demo, choose Prototype Demos; if you have clear feature requirements and a technical plan, choose Code with Spec.
2. **Describe the destination, not the route**: "Make a movie recommendation app" is far worse than "Make an iOS app that recommends 5 movies a day, supports swiping up and down to browse, and allows favoriting." Say clearly "what you want" and let the AI decide "how to do it"—the first version's completeness will be much higher.
3. **Don't panic when you hit errors**: Screenshot or copy the error message and send it straight to Qoder; it can pinpoint most environment setup issues.
4. **Install a few Skills**: If you're building front-end pages, install `frontend-design`; if you're doing a content-type project, install `seo-content`. The difference before and after installing is visible to the naked eye—the earlier you install, the sooner you benefit. Head to skills.sh to see what suits you.
5. **Start with Vibe, finish with Spec**: It's fine to use Prototype Demos for quickly validating an idea. But if what you're building is more than a demo, seriously consider starting with Code with Spec. Spending 10 minutes writing the requirements clearly (what features you want, what you don't, and what the acceptance criteria are) is far more worthwhile than spending two hours in pitfalls later. The clearer the intent, the lower the chance the AI goes astray.
## Looking Back
From opening Qoder to building an app that runs smoothly on an iPhone, I didn't write a single line of code the whole way.
One thing surprised me throughout the process: I didn't feel that "being dragged along by the AI" anxiety. Thinking about it, it probably has to do with Quest mode's rhythm—it first asks what you want to build, pops up question cards to let you quickly clarify intent when things are unclear, and only executes autonomously after confirmation.
Looking back, Qoder Quest helped me turn an idea into running code, while Skills backstopped the design and performance areas I know nothing about. Without Skills, the app would most likely still be at the level you can tell at a glance was "AI-made."
I hit quite a few pitfalls along the way: environment setup took two hours, and in the end I had to cut a requirement for the share feature. But every time I hit a wall, the reasons looking back were about the same: either I hadn't thought clearly about what I actually wanted, or I underestimated the constraints of reality. The solutions weren't fancy either—just stop, think it through again, and then let the Agent get to work.
"Daily Movie" isn't perfect, but I built it (okay, Quest built it, but the idea was mine). The biggest takeaway after finishing wasn't "turns out I can do it too," but the discovery that when it comes to collaborating with an Agent, whether you can code really doesn't matter that much. What matters is whether you can clearly articulate what you want.
If you also have an app you've long wanted to build, don't wait until you're "ready." Open Qoder, switch to Quest mode, say your idea out loud, and start from a running version. You'll definitely hit walls along the way; when you do, stop and think: what do I actually want, and what can I do without for now.
A non-technical operations person built an app tailored exactly to their own taste. Come to think of it, that's pretty interesting.
# How to Use Qoder on Legacy Projects? A Hands-On Guide from Confusion and Pitfalls to Self-Iteration
> Using Qoder's Repo Wiki and Skills to turn a legacy project from "afraid to touch" into self-iterating.
Hi everyone! I'm Yue Yangbo, a backend development engineer. I'm glad to have the chance to explore with you: "How to use Vibe Coding for programming on legacy projects."
## 01 Legacy Project Problems and the Breakthrough
1. **A huge codebase**: Our legacy project may have tens of thousands, hundreds of thousands, or even millions of lines of code—an enormous scale.
2. **Highly complex historical logic**: Because it's a legacy project, staff turnover and requirement changes have been very frequent.
3. **Very high cost to understand**: For a newcomer, understanding, learning, and improving the project can take days or even weeks.
When I had analyzed the problems of the legacy project, I started to wonder: if AI could understand the project, wouldn't it be able to write good code? That was my very first thought when I began doing Vibe Coding.
### Repo Wiki: Turning AI into a Mentoring "Senior"
Qoder's Repo Wiki helps us quickly understand the project architecture, map out the call relationships, and generate detailed documentation. At the same time, it can also help the team onboard new colleagues.
In the past, onboarding a new colleague involved a fairly heavy mentoring process, and that process consumed time on both sides. Typically, I would first walk them through the project, give an overall introduction, and help them build a basic understanding; then they would read the code and docs on their own. Even that wasn't enough—afterward they would repeatedly come back to me to communicate, confirm, and ask questions. Only after several rounds could they reach a relatively deep understanding of the project.
After using Repo Wiki, this changed. Because the system had already organized the project into fairly complete documentation, a new colleague no longer starts by finding a person—they start by "asking the project" in Ask mode. Most questions are actually resolved at this stage, covering roughly 80%. By the time they come to talk to me, they bring the remaining 20%—the more critical, more targeted questions. This way, the learning path shifts from "person mentoring person" to "self-service first, then deep discussion." New colleagues get up to speed faster, and the time both sides invest drops noticeably.
## 02 Pitfalls and Attempts
Even though I had gained some understanding of the project, the problem of writing code wasn't solved by that alone. At first, my approach was very direct—I asked the AI to implement specific features.
The AI could quickly output large amounts of code snippets, but when actually run, quite a few bugs and deviations showed up. So I kept adding clarifications, describing and correcting the problem a second, third, or even more times.
However, things didn't move toward what I expected—instead they gradually spun out of control: the code became messier with repeated changes, and the logic got harder and harder to keep in check. In the end, I even reached a state of "not daring to change it anymore."
I looked at the problem from a different angle: if I treated the AI as a colleague, could they really do the job well given descriptions like these? Today's AI is already very capable—in a sense, it can indeed be treated as a "newly onboarded colleague." But the question is: faced with vague, fragmented, and constantly changing descriptions, can it really understand accurately?
Thinking this through, I gradually realized the problem might not lie entirely with the AI, but comes back to ourselves: is the information we provide clear, specific, and executable enough? Based on this insight, I began a new round of attempts.
### Attempt 1: Make Requirements Concrete
I began to adjust the way I expressed myself—no longer just saying "what feature to build," but trying my best to explain the details clearly and specifically.
If you simply throw out a huge feature, the AI's understanding of the requirement often diverges from ours. So I started adding more constraints and background information, and even began with very small tasks, such as "add a field to a PO" or "write a simple calculation utility class."
What I want to emphasize more is this: this isn't just about completing tasks—it's about building a communication mechanism with the AI. Just like when a new colleague joins, you need to gradually learn how they work. Through these small, concrete features, I slowly figured out its "habits," while it also adapted to the way I express things. The smaller and finer the requirements are broken down, the more precise the communication, and the more controllable the final result.
### Attempt 2: Ask Proactively—Align First, Then Write
Once, during an interaction with the AI, I noticed a detail: when I gave it an implementation approach, it didn't blindly follow along—instead it would point out "this approach might not be ideal," and even offer better suggestions.
I began to reflect: perhaps the issue wasn't about "making it do the work," but about "how to align with it." So I gradually shifted from "commanding" to "asking proactively." Instead of directly telling it to write code, I first describe my requirement and design ideas, for example: "I have a requirement like this, and here's my design—could you check whether it's reasonable?"
This change brought two clear benefits: on one hand, the AI can better understand your thinking and context; on the other, it can fill in details and approaches you hadn't considered. After this, I adjusted my workflow accordingly: first complete alignment through questions, then move into writing code.
### Attempt 3: Control the Context Length
Through continued use, I gradually found that if you keep piling new requirements into the same conversation without controlling context length, the AI's understanding easily drifts. Especially when the context gets very long (for example, approaching 200K), information starts to get mixed up, key points get diluted, and the AI's "judgment" clearly declines.
From practice, I lean toward keeping the context within a relatively controllable range—roughly 20%–30%—where the overall results are more stable. When the requirements themselves are many and messy, my approach is to actively break them down: split one big requirement into several small ones and handle them in separate conversation rounds. This not only effectively controls context length but also makes each step's result clearer and more controllable.
### Attempt 4: The Minimal-Commit Principle
This one is actually a lesson learned after getting burned. The previous rounds of coding and review had gone smoothly, but in one later case where the description wasn't clear enough, the AI mistakenly modified code I had already adjusted. The earlier results were overwritten, and nearly a full day of work was wasted.
This made me realize that once the code is usable and has passed review, you should commit immediately. That way, even if later changes go wrong, you can quickly roll back to a stable version and avoid the waste of redoing work.
## 03 The Skill Universe: Let AI Reuse Your "Habits"
The methods above can already support us in developing most basic features. But with them comes a new problem: the code the AI generates often doesn't fully match our code style or the company's business conventions.
To address this, I tried solving it through Skills. I call this system the "Skill Universe"—here, the AI is no longer just an assistant tool, but more like an "avatar" of you. It not only understands your requirements but also gradually reuses your habits, conventions, and standards.
By building different Skills, we can distill code style, common logic, and even business constraints, so that when the AI generates code, it naturally fits the way we work—rather than starting alignment from scratch every time.
### How to Build a Skill (Method and Practice)
It's actually not complicated. We can directly describe our requirements in Ask mode, and at the same time tell Qoder our existing method designs, code style, and agreed-upon rules, letting it generate based on that information.
In actual use, if you find the generated result doesn't match expectations, there's no need to keep correcting it in the conversation—instead, go back to the Skill file itself and adjust the descriptions and rules within it. It's worth emphasizing that this isn't achieved in one go; it's a process of continuous optimization and ongoing iteration.
Here's a more practical example. In day-to-day business development, we've often already distilled some fixed conventions, such as: a unified exception-handling utility class, a specific way of building queries, and so on. Without constraints, during Vibe Coding the AI can generate code that "looks correct" but very likely doesn't conform to our business conventions. At that point, we can split and categorize these conventions and distill them into different Skills, used to constrain and guide the AI's generation behavior.
Next, let's look at a concrete hands-on case to see how this approach plays out in practice.
In an experiment based on a Spring Boot backend project, I focused on two pain points:
1. Exception handling: Our business definitely has its own exception utility classes.
2. Query encapsulation: JPA has multiple query approaches (interface methods, native SQL, criteria building, etc.). If you let the AI write it on its own, it will use various practices that don't necessarily conform to the project's conventions.
Experiment comparison:
- Without Skills: The AI wrote native SQL using JPA-defined methods and didn't use our custom Error methods. The logic was fine, but it didn't meet expectations.
- With Skills: I had pre-built a "Query Skill" and an "Exception Skill." When generating code again, both the dynamic query building and exception throwing automatically used our own business utility classes.
## 04 My Workflow and Self-Optimization Mechanism
After a series of attempts, I gradually distilled a relatively stable development workflow:
Starting from requirement breakdown, I first align the requirement in Ask mode, then move into Agent mode to implement the code; afterward I do a code review, and once confirmed correct, commit promptly.
The overall flow can be summarized as: Requirement breakdown → Align in Ask mode → Modify code in Agent mode → Code review → Commit promptly.
Most people, when first encountering Vibe Coding, go through a stage where "the results aren't ideal." But the question is: can we, like large models, keep iterating on ourselves?
I've summarized a simple self-optimization mechanism:
When the result is a success, distill the effective methods, organize them into a personal knowledge base, and form reusable experience;
When the result isn't ideal, do a root-cause analysis to find the source of the problem. Looking further, the problems roughly fall into two categories:
- Uncontrollable factors: such as the limits of the model's capabilities. In this case, consider adjusting the model or switching tools in time;
- Controllable factors: such as prompts that aren't clear enough, flaws in the business logic itself, code structure that needs refactoring, or not being proficient enough with the tool (for example, not clearly distinguishing between Ask mode and Agent mode).
Through this kind of continuous review and correction, you're essentially letting your own ability to use the tool gradually "evolve."
## 05 Can Qoder Only Write Code?
My answer is: not necessarily.
Writing code is only part of our work, not all of it. Qoder's capabilities go far beyond that—it can also be used to write scripts, polish hit articles, and even brainstorm video scripts.
When you open up the boundaries of how you use it, you'll find it's not just a "code-writing tool," but more like a partner that can participate in thinking and collaborate on creation.
Based on this idea, I made an even more interesting attempt—letting Qoder "define itself."
I had it write lyrics, come up with a name, design a cyberpunk-style character, and even create storyboard prompts for an MV. These pieces were gradually strung together, and finally, guided by Qoder's "brain," I completed a full MV—"I Am Qoder."
One last thing I want to say to everyone: let's start using it first, then gradually grow stronger.
# One Person + Qoder Did the Work of 20 People in 3 Months: The AI Command Skills I Learned by Spending Hundreds of Thousands of Credits
> Made good use of Qoder to build an AI-native dev system—1 person, 2 months, delivering what once took 20 people 3 months (an MES product).
Hello everyone, I'm Li Yuzhong, Product Technology Lead of Guanjiapo Huihuang AIMES. In an era when artificial intelligence is sweeping through the programming world, many developers are still watching from the sidelines, or feel frustrated because "AI-generated code is unstable." As an "old programmer" with 22 years of experience, I believe that a single person is enough to complete what a team of 20 used to accomplish in three months. This is no fantasy—it is the result of the reconstruction of "engineering discipline" in the AI era.
## 1. The Turning Point in Mindset: AI Is an "Intern," Not an "Omnipotent God"
Many people feel frustrated when they first use AI for programming, because they treat AI as a "god." But in reality, AI is essentially an "intern" with extremely powerful capabilities yet no business intuition whatsoever.
If you throw a coding instruction at AI and let it guess your intent, the result is usually chaos. AI doesn't understand your business, nor does it understand the logic a company has accumulated over 30 years. Therefore, transitioning from "coder" to "architect" is a path every developer must take—what you do is no longer writing code, but "commanding" and "defining."
## 2. Why Choose Qoder
When I first started, I took many detours. I only knew it worked fast; I didn't know how to write rules or how to write skills. At the very beginning I burned through more than a hundred thousand Credits, over 8,000 yuan a day, and at the time it felt amazing. But later on, the AI couldn't keep going, because it couldn't even modify its own work—all because I hadn't done much of the preparatory work up front.
Later, I rebuilt a very important part of the ERP—MES (Manufacturing Execution System). With just myself plus Qoder, I built a product in two months, and it's already being demoed and sold.
**The advantages of Qoder lie in:**
1. **"Solution Encapsulation" Matters More Than "Model Selection"**
The model itself is just a tool, whereas the core value of Qoder is that it "makes the choice for me." The Qoder team continuously evaluates and integrates the most powerful large models currently on the market, packaging them into a mature, engineered product. This "packaged practical experience" saves me the effort of frequently switching models and studying the underlying details, letting me directly use the most cutting-edge technical capabilities available today.
2. **The Efficiency Dividend from "Engineering Wrapping"**
AI development is essentially an engineering problem. Qoder is not just a model interface; it does deep engineering work at the application level. It tightly binds AI capabilities with the developer's IDE environment and project codebase. This "engineering wrap" makes AI's output far more productive, rather than staying at the level of mere chat conversation.
3. **A Deep Accounting of "Cost-Effectiveness"**
I chose it not out of "worshipping foreign things" or "blindly following the crowd," but based on the optimal cost solution:
Time cost: Using the strongest combination of tools significantly boosts coding speed and greatly reduces the number of bugs. Opportunity cost: A person's time is a constant 24 hours. Making a product in the shortest possible time to seize the market window is far more important than fussing over model subscription fees. Deployment cost: Once you factor in labor costs and delivery cycles, Qoder's compute consumption is far cheaper than hiring real engineers—it's a rational business decision.
4. **A Leading "Expert Team" (Agent) Collaboration Mechanism**
Qoder's Expert Team mode (Agent) has completely changed the relations of production. It simulates the collaboration logic of a real human team—there's a Leader who directs, members who report, and review and correction.
Work paradigm: Previously I had to manually open multiple windows to work in parallel; now, through Agents, it can automatically assign tasks and perform internal verification. Value manifestation: This mechanism breaks down, executes, and reviews complex software development tasks, greatly restoring the rigor of a human team. Although it consumes more compute, the stability and high quality of its output make it far more economical than manual error correction.
## 3. The Core Contradiction of Enterprise-Level Implementation
The biggest contradiction for enterprises implementing AI is not that "AI is unstable," but the "human's ability to command."
If someone internally says "AI is unstable," it's often because they can't master AI. AI is essentially a tool that executes according to specifications; the quality of its output depends directly on the precision of the rules (Spec) you input. AI is a powerful "intern," not a reliable "engineer." It has extremely strong execution ability but lacks business experience and a global perspective. Therefore, trust but always verify. Don't expect AI to guess your intent. Treat AI as a new team member and manage it through institutionalized, standardized means—only then can you truly achieve the efficiency transformation of "one person doing the work of ten."
## 4. Core Methodology
### SDD (Spec-Driven Development): Specification-Driven Development
At first I didn't know what SDD was. Once you use it, you'll find that if you don't write specs, if you don't write these things, the AI later becomes an idiot. You ask it to fix something, and it can't. If we hand old code—the kind of "shit-mountain code"—to AI, it becomes an idiot, because it's all wrong inside, with no rules. What is the most core thing in software engineering? Doing things by the rules—that's what returns us to the essence. The core of a computer is input, computation, output; if you don't even have rule-based input, how can it give you rule-based output?
The core of AI coding is "specification precision." SDD is about converting traditional development requirements into extremely precise engineering specification documents.
Before generating any code, you must define field types, validation rules, UI presentation, and so on. The more detailed the "constraints" you provide, the higher the quality AI delivers. After writing the Spec, you must require AI to simultaneously generate a complete set of test cases, achieving closed-loop verification through automation and avoiding the repetitive labor of humans manually hunting for bugs.
By using clear Specs to constrain AI's behavior, you turn abstract requirements into executable boundaries. This is not only about regulating AI—it's also about re-organizing the team's development logic. Without constraints, there is no quality; without rules, AI merely repeats your mistakes.
### Skills: Reusable Behavioral Paradigms
From personal tools to team infrastructure—if you have no skills, it's all in vain. ERP boils down to nothing more than three big pieces: basic information, documents, and reports. When a new employee arrives, I'll finish writing the product information and tell them: for business partners, just follow my example. That's a skill.
Skills abstract complex business logic into "modular skills" that AI can invoke. Their essence is solidifying the industry experience, coding habits, and architectural decisions you've accumulated over many years into an "engineering operation manual" that AI can understand and execute. Construction path: First, through in-depth communication, get AI to nail one document (such as a purchase order), then distill it into a general Skill. When you do a similar task later (such as a sales order), you directly invoke that Skill and finish in a few minutes.
Skills are not set in stone; they are iterated through weekly summaries and retrospectives, and they are the core assets of both the individual and the team.
### Memory: The Enterprise's Persistent Knowledge Base
Memory solves AI's "context discontinuity" problem across different business scenarios.
Like human employees, AI needs to have "memory" of the project. As project complexity grows, Memory ensures AI can understand the difference between version 10.0 and version 11.0, avoiding forgetting and logical confusion.
All Memory is essentially structured data (such as specific folder directories). By copying this Memory, you can quickly let a new project inherit the business capabilities of an old project, achieving seamless knowledge transfer.
From personal memory to team memory: Memory should not belong only to the individual; it should be a shared knowledge asset of the team.
### The Three-Layer System of Rule + Memory + Skill
Let Rule guard the bottom line, Memory record the standards, and Skill deliver the capabilities—only when these three layers work together do you have complete AI Coding engineering.
## 5. Pitfalls and Lessons Learned
### Problems Encountered
● **Context Pollution**: As the project iterates, long-running conversations lead to context redundancy and even contradictions. Lesson: Clean up regularly, and require AI to re-organize based on the current Rule, Memory, and Skills.
● **The AI Hallucination Repair Loop**: If AI still can't solve a specific problem after three attempts, it means it has fallen into a mental dead end. Lesson: Switch conversation windows in time; don't stubbornly grind away—learn to "communicate from a different angle."
● **Rule Drift**: Unsupervised AI easily deviates from predetermined coding standards. Lesson: You must set mandatory "red line" rules (such as SQL injection prevention and coding standards) to ensure AI won't break the bottom line in pursuit of speed.
● **Over-Reliance**: Assuming there's nothing wrong with what the AI writes is extremely dangerous. Lesson: Enforce a mandatory Review process + manual review of key modules.
### Lessons Learned
Don't expect AI to guess your intent. When I build a document, I define the structure, types, validation rules, and discount presentation, then let Qoder load it and write the front end, back end, and interfaces according to the rules, then run tests. This not only writes code—the best part is that I now write all of my industry solutions with AI, because it has my entire knowledge system.
Many people say AI is unstable. If a colleague is still saying "AI hallucinates a lot," don't listen—it's because they can't command it. If your Spec is written well, I'm telling you the output quality is very high, higher than the quality of everyone we had in the past. When it works by the standards, its execution ability is extremely strong.
## 6. Conclusion: Extending the Dimension of Life
Me alone plus Qoder is equivalent to doing the work of 20 people over three months. Having walked this path for so many years, my biggest feeling is that the dimension of my life has been extended. Things I used to say I could only do at 80, I might get done by the time I'm 50. We used to spend five years validating a project only to fail; now in a few months I know whether something can succeed.
Technological change brings commercial change, and only when commerce changes do you have an opportunity. Twenty years ago I was staying up late writing code; ten years ago I was doing cloud transformation; today, 20 years later, technology has changed. If there are any entrepreneurs among you, remember: the essence of AI Coding is command. Feed your memory and knowledge to AI as "private-domain knowledge," and it will be your strongest intern.
As long as you have ideas, you can create a great many things. Engineering records matter even more, because the stronger AI's capabilities become, the more it will fail to work the way you want without your constraints and conventions.
# From "Help Me Patch Code" to "Deliver the Project for Me": How Hisense Reshaped Its Development Workflow with Qoder
> Hisense built a complete AI-native development system with Qoder, improving new system development efficiency by 3–4x.
The Digital Quality Center at Hisense Group serves 46 product companies across the group, covering more than 100 self-developed systems in R\&D, manufacturing, supply chain, marketing, and other domains. The technology stack is diverse and the legacy burden is heavy — no single development model could accommodate this diversity.
What troubled the R\&D team most was never "not being able to write code." It was this: when newcomers took over legacy projects, documentation was missing, knowledge was fragmented, and the learning curve was steep; a great deal of time was spent on repetitive work; online error troubleshooting was time-consuming, and code reviews could not catch every hidden risk.
When large language models surged in 2023, we saw the possibility of solving these problems. But the programming tools at that time only stayed at the level of "local completion," while network stability and security compliance were non-starters.
## Turning Point: Introducing Qoder, Upgrading from "Assisted Programming" to "Autonomous Programming"
In January 2025, as the SDD development model matured, we began product exchanges with the Qoder team. In February, we organized a pilot with nearly 100 people, and in March, Qoder was officially introduced. To date, more than 900 people are using it.
The essential difference between Qoder and earlier tools is that it is not just a completion engine, but a complete AI-native development workbench — Rules, Skills, Memory, Repo Wiki, and expert panel collaboration together form all the infrastructure we need to land AI-native development.
## Leveraging Qoder to Build the Harness Engineering System
Around Qoder's capability matrix, we built an internal engineering system called Harness — used to "harness" AI so that it could deliver stably across 109 systems.
### First, We Classified the 109 Systems by Scenario
● **High-code scenarios (accounting for more than 70%)** — further divided into three categories:
● Category A: new system development from scratch, with Qoder participating throughout;
● Category B: new module development on legacy systems, using Repo Wiki to understand existing code before generating;
● Category C: modification of existing modules in legacy systems, requiring a large amount of historical knowledge to be injected before the Agent steps in.
● **Low-code scenarios** — mainly using Qoder to generate configuration logic and glue code;
● **Other scenarios** — such as documents, test scripts, and other auxiliary outputs.
### Around These Diverse R\&D Scenarios, We Distilled Four Core Pillars of Harness
#### 1. Spec-Driven Development
Qoder's Quest-SDD (Spec-Driven Development) turns requirements directly into executable development specifications. The granularity and clarity of the Spec directly determine the quality of the first code generation, and also affect the number of subsequent human-AI interaction rounds. We conducted two real-world practices:
**Practice 1: Big Spec vs. Small Spec.** The big Spec had 300 lines and 75 tasks; the small Spec had 70 lines and 12 tasks. The result — the big Spec's first-pass completion rate was only 60%, and it took dozens of additional conversations to barely finish; the small Spec reached a 95% first-pass completion rate.
**Practice 2: The Same PRD, Three Ways of Handling It.** Letting Qoder generate the Spec directly → first-pass completion was only 70%, and more than 50 rounds of clarification were still needed. After engineers and product managers aligned line by line and updated the Spec → completion improved significantly. Adding human-machine alignment (letting the Qoder Agent ask questions to confirm understanding) → completion approached 100%, with basically no follow-up modifications needed.
From this, we established Spec quality standards:
● Under current mainstream model capabilities, a single Spec should in principle be kept under 100 lines and no longer than 150 lines;
● Every constraint must be convertible into a test case to ensure requirement clarity and verifiability, and to provide a basis for subsequent AI verification;
● If a single Spec requires more than 10 rounds of human-machine correction after code generation, the original Spec quality is likely insufficient, and we should return to the Spec stage to realign.
#### 2. Harness Feedback Loop
We say that AI Coding has entered the AI-autonomous stage, characterized by building feedback loops to realize "Human on the loop," executing long-cycle tasks through multi-agent collaboration, and completely liberating humans. With Qoder and various open-source Skills, we were able to quickly build multi-agent feedback loops. On the one hand, in the loop, applications undergo AI verification and review, with automatic repair, ensuring that the software gradually converges on requirements. On the other hand, every workflow process can precipitate knowledge, enabling optimization of Harness.
We believe that testing becomes even more important in AI development, because model hallucination objectively exists and testing is an important means of combating it. After AI generates a Spec, test cases must be generated simultaneously, and the test cases must be strictly reviewed, especially to ensure completeness of boundary conditions. Test cases should be included in the Git repository as an important component of Harness. The testing Agent must use a different model from the coding Agent. In practice, we found that asking the Qoder Agent to fix all defects at once often yields poor results; but asking it to fix only one defect at a time works very well.
Similarly, running 100 test cases in 10 batches across 10 independent contexts yields more defects found and lower missed-detection rates than merging them into one context for a single test run.
Therefore, our feedback loops always break tasks down to the smallest granularity — small-batch execution, fix one by one, and continuous verification. Qoder's Agent capabilities make this high-frequency iteration feasible.
#### 3. Constraints & Guardrails
With 109 systems and diverse technology stacks, keeping architecture from drifting over long-cycle iterations requires constraints that are no less important than capabilities. The core principle is simple: without guardrails, the more AI produces, the faster the codebase entropy grows.
Around this principle, we built a set of specifications and Skill systems covering the entire development chain, managed in tiers by priority: P0 locks down architectural boundaries and compliance baselines, P1 covers coding core, and P2 focuses on maintainability. At each stage, the corresponding combination of constraints is injected on demand to limit Agent behavior boundaries and let AI work within the correct framework.
#### 4. Knowledge Dissolving: Realized Through Qoder Repo Wiki
Knowledge governance is the foundation that continuously increases the value of the first three capabilities. We carry it through a three-layer system of AGENTS.md + Repo Wiki + Skills.
**AGENTS.md** is a project-level structured knowledge map — an approximately 100-line entry file serves as a directory navigator, appropriately replacing bulky, comprehensive manuals. It uses progressive disclosure to push the information needed by AI on demand at different stages of a task, reducing context redundancy. Each project's architectural decisions, coding standards, technology stack conventions, and known pitfalls are all structured and accumulated, so that new members and new Agents reading the same AGENTS.md gain a consistent project understanding.
**Repo Wiki** automatically generates and continuously maintains project documentation — complete structure, with code references, intuitive and clear. After code updates are committed, the Wiki is synchronized and updated, keeping design and implementation aligned — something that was almost impossible in the past.
**Skills** turn individual experience into reusable organizational capability. These are not "configuration files," but the real moat for enterprises using AI. With this knowledge, AI is no longer a newcomer but a seasoned hand trained by the enterprise.
## Real Numbers: Efficiency Gains from Running Qoder
We selected 10 pioneer projects for the pilot:
● For new system development, conservative estimates show a 3–4x efficiency improvement, with go-live times greatly accelerated. By year-end, we expect to reach 5–6x.
● Development on historical systems showed limited improvement — the main bottleneck being the implicit knowledge in legacy baggage that needs to be gradually extracted and injected through Qoder Rules.
Projects that improved well shared one common trait: in the early stages of development, they did not rush to generate code, but spent a lot of time aligning requirements in Qoder Spec. The requirements phase accounted for more than 40% of the entire development process — only after requirement quality was up to standard did they move into the generation phase.
## Qoder Is Changing Our Development Process
To unlock the ultimate efficiency of AI-native development, tool improvement is only half the equation; the other half is process adaptation. Around Qoder, we are exploring a new process:
### 1. Iterative Cycles Replace Linear Delivery
In the past, the process was linear: requirements → design → development → testing → deployment, with handoffs at every stage. Now coding, testing, and review form a continuous loop within Qoder, and "small steps, fast running" moves from concept to daily practice. Iteration on long-cycle tasks no longer causes architectural drift, because constraints and context remain online.
### 2. Testing Shifts Left to the Requirements Stage
At the requirements stage, Qoder is used to generate test cases covering boundary conditions. Every constraint in the Spec must correspond to a verifiable test case — this is the key defense line against model hallucination later on. Test engineers shift their focus from "finding bugs" to "reviewing test case quality."
### 3. Role Focus Shifts
Development engineers no longer write code line by line, but focus on result review, architecture drift detection, and knowledge accumulation. Test engineers focus on test case quality and result review. Product managers deeply participate in Spec quality control.
Process reshaping is the work that yields the greatest returns. We are still exploring, but the direction is clear — redefine the boundary of "what humans do and what AI does" around Qoder.
## Three Recommendations for Enterprises Exploring AI Coding
### Step 1: Choose the Team First, Then the Project, and Get AI-Native Development Running
Do not roll it out to everyone at once. First find a small team willing to embrace AI, and choose a new project as the starting point. New projects have no legacy baggage, making it easiest to run through the complete chain from requirements to delivery, and easiest for the team to build intuition about AI capabilities. Use it first, see results, then talk about scaling.
### Step 2: Build Harness by Scenario to Make AI Output Stable and Controllable
After the pilot is running, gradually build the Harness engineering system for different business scenarios. AI development without Harness has uncontrollable output, architecture prone to drift, and quality dependent on luck. The value of Harness lies in using specifications, constraints, and feedback loops to frame AI's behavior boundaries, so that every output is stable, predictable, and reviewable.
### Step 3: Treat Knowledge Accumulation as a Long-Term Moat
Rules, Skills, AGENTS.md, and Repo Wiki — these are not "configuration files," but the real moat for enterprises using AI. With Qoder's knowledge system, accumulate the team's architectural decisions, business rules, historical experience, and technical standards as digital assets. The gap between AI tools will gradually narrow, but the accumulation of enterprise private-domain knowledge is irreplaceable. When knowledge governance is done well, AI is no longer a newcomer but a seasoned hand systematically trained by the enterprise — this is the real long-term moat.
## Closing Thoughts
Our work used to be "human-led, tool-assisted." Now it is becoming "human and Qoder co-producing."
The most important capability for engineers is no longer writing code, but clarifying intent, breaking down requirements, and building the environment. Qoder helps us solve tedious, repetitive execution, so that creativity is no longer limited by "not knowing how to write a certain kind of code."
We have already seen the direction — Spec quality determines software quality, process adaptation determines the ceiling of efficiency gains, and the knowledge accumulated on Qoder determines the long-term moat. The future of R\&D is a process of humans and AI evolving together.
# The Intelligent Leap of SaaS Global Expansion — How Eccang Reshapes R&D and Operations with Qoder + QoderWork
> Eccang uses Qoder to break the boundary between technical and non-technical teams, evolving from "tool users" to "agent managers."
A Top 3 SaaS company serving tens of thousands of cross-border sellers, with core business processes spanning over 20 stages and covering tax laws and exchange rates across multiple countries — yet this year, it did something that surprised its peers: it introduced Qoder, starting with 1,500 seat-months and covering both R\&D and non-R\&D staff.
This was not an impulse purchase. It was Eccang Technology's most honest response to the idea that "AI is not a choice, but a must-answer question."
## The Cross-Border E-Commerce Business Is Far More Complex Than You Think
To understand why Eccang made such a big commitment, you first need to see how difficult its business really is.
Eccang's two product lines — ERP and WMS — support sellers through the entire process of selling from China to the world. A single shipment from China to the U.S. involves more than 20 key steps. Every step is a potential pitfall: different countries have different tax laws, exchange rates, time zones, and platform policies; Amazon, eBay, and independent stores each operate by their own rules; bosses, operations staff, finance teams, supply chain managers, and overseas warehouse leaders must collaborate in highly complex ways; SKU management, cross-border financial consolidation, and real-time warehouse scheduling are all indispensable.
As Eccang CMO Gong Zhihao put it: "In the past, sellers profited from information gaps. Now they need brand globalization, compliance, and profitability. The system used to be a ledger; now it needs to be a radar and a brain."
Sellers want faster, more accurate, and more manpower-efficient services, all while maintaining stability. These four demands weigh heavily on R\&D — the pressure is easy to imagine.
So the question becomes —
## How Does a 200-Person R\&D Team Handle Massive Demand?
Eccang's VP of Technology Mo Mingyi chose not to simply add headcount.
Earlier this year, he restructured the entire product and R\&D team by product line and technical engineering, breaking it down into finer-grained collaboration units specifically adapted to the AI Coding team model. What does this mean? It means the entire chain from requirements to delivery has been redesigned around "human-AI collaboration."
In the past, product managers wrote documents, UI designers produced graphics, front-end developers built interfaces, back-end developers built systems, and QA conducted acceptance testing. The chain was long, and every step introduced losses; information decayed continuously as it was handed off.
Now, things are completely different. Requirements already interact with AI at the documentation stage — documents are converted into Markdown formats that AI can more easily understand, and product managers can shift left to quickly produce demos for validation. More importantly, front-end and back-end code can now be written together. AI understands the entire project structure, so communication between front-end and back-end no longer relies solely on an API document as the single interface.
The most obvious change Mo Mingyi observed is this: **Mid-level engineers can now independently design complex systems.** Tasks that previously only senior architects could handle can now be tackled by mid-level engineers with Qoder. He himself is an example — a new project he had planned to hire two people for was eventually completed by one person using Qoder and went live quickly.
But a new question arises: with so many AI coding tools on the market, why did Eccang settle on Qoder?
## Why Qoder? Four Reasons
Mo Mingyi's answer is straightforward and pragmatic.
**First, the toolchain is complete.** From document management to the full R\&D workflow, Qoder includes expert teams, custom agents, and Skill packaging. These are not nice-to-have features; they are infrastructure that transforms individual capabilities into organizational capabilities. Eccang doesn't want a few programmers using AI to improve their own efficiency — it wants the entire team collaborating with the same tools and the same language.
**Second, stability.** As an organizational productivity tool, stability is a hard requirement. Qoder has proven reliable in this regard and is suitable for long-term enterprise use. As Mo Mingyi put it clearly: "This is an organizational productivity tool, not an individual behavior."
**Third, reverse documentation capability.** RepoWiki generates documentation with one click, reverse-engineering the logic of legacy projects into standardized documents. Eccang has been around for 13 years, and its architecture has been upgraded countless times. Documentation is updated every year, but everyone knows how thoroughly it is actually updated. Now AI can reverse-engineer directly from the code, which is equivalent to giving legacy projects a thorough "health check."
**Fourth, team management.** The backend shows each employee's consumption, usage ratio, language preferences, and team efficiency metrics, and allows Token allocation on demand. Management is no longer a black box.
With the selection made, how did it actually perform?
## Four Real-World Cases of Qoder at Eccang
Mo Mingyi gave several recent examples.
**Development manpower savings:** A project he had planned to hire two people for was completed by one person using Qoder and is now live. This is not a proof of concept — it is a real product.
**Logistics page restructuring:** A product manager felt the logistics quote page was too complex and wanted to change it. In the past, this would have required back-and-forth with the tech team, with long communication cycles and uncontrollable outcomes. Now the product manager can handle the page interactions and validate with AI independently, quickly deciding "whether this can be done" — without waiting for the tech team's schedule feedback.
**Internal CRM implementation:** Completed in ten days and rolled out company-wide the following week. In the past, such internal demands always ranked behind business needs, and buying an external solution cost money. Now Qoder has made it lightweight. The question is no longer whether resources allow it, but whether it is a priority.
**Delivery model transformation:** From "writing code" to "defining requirements + reviewing output." In Mo Mingyi's own words: "Write it, and it's done." This means developers no longer dwell on syntax details but focus on whether the business logic is correct and whether the architecture design is sound.
But at this point, many companies will ask a more fundamental question —
## How Does Qoder Ensure Enterprise-Grade Security?
Cross-border ERP involves finance, inventory, and orders — data security is the bottom line. Deng Zhanzhao, Senior AI Business Manager at Alibaba Cloud, answered this question from three levels.
First, environment isolation. Qoder and QoderWork are both deployed in a sandbox environment on local PCs. Code operations, generation, and execution do not leak outside; data never leaves the machine.
Second, permission control. Fine-grained access control protects core modules, with different roles accessing different levels. For example, when modifying order settlement logic, Qoder first analyzes which other modules depend on this module and provides impact reminders — so programmers can see at a glance what changes will affect.
Third, generation validation. Every piece of generated code undergoes security analysis, vulnerability scanning, and dependency conflict detection, and only enters the repository after multiple validations. It can also automatically generate test cases to support defensive programming.
Finally, human-AI collaborative acceptance. AI-generated results are reviewed and decided by developers; humans move from executors to decision-makers. Qoder elevates the human role one level up.
With security addressed, Qoder's penetration at Eccang goes far beyond the R\&D team.
## Beyond R\&D: "Technical Democratization" for Non-Technical Teams
The 1,500 seat-months are not just for programmers. Eccang's marketing, operations, and customer service teams are all using QoderWork.
Gong Zhihao shared his experience. A product PPT page used to take 1–2 days; now it takes 15–30 minutes. A conference-level PPT can be generated in less than half a day. This is not crude work — if your aesthetic sense is good and your descriptions are precise, the output is genuinely usable.
The change in official website construction is even greater. The marketing team used to have to request slots from the tech team, and customer needs always came first, leaving marketing requests at the bottom of the queue. Now Gong Zhihao uses QoderWork himself: he throws the old website in, lets AI analyze the problems, and AI outputs eight diagnostic items. Then he asks AI to redesign it, and the resulting prototypes are taken directly to team meetings. He jokingly told Mo Mingyi, "My credits are running out a bit fast — can you add some?" — because 80% of the pages were already built by AI.
Customer service is also changing. The customer operations team uses Skills to package common scripts, and logistics reconciliation and complaint handling now run through AI workflows without waiting for tech team scheduling. Gong Zhihao also packaged a Skill for sellers that finds 1688 factories from Amazon hot products. When sellers saw the results, they asked, "Was this edited?" — No, that was the level AI produced directly.
Gong Zhihao summed it up in one sentence: **"Humanities professionals now have productivity. It used to be the privilege of STEM professionals; now everyone has it."**
This "technical democratization" is not only reflected internally, but also in Eccang's customer-facing products.
## Mado AI: Building an AI Product the Qoder Way
Mado AI, launched by Eccang this year, does not stack features on top of the old ERP. It is rebuilt from scratch in an AI-native way.
This decision itself is a story. At the time, there were two options: one was to add AI features to the existing system, and the other was to rebuild it in an AI way. Eccang chose the latter. The reason is simple — only AI-native architecture can follow AI's value chain.
The entire project team was newly assembled, and the toolchain, Skill management, scenario configuration, and agent publishing were all completed on the Qoder platform. The delivery model has completely changed — instead of writing large amounts of code and manual configuration, the team now only needs to understand customer needs, produce Skills, configure scenarios, and publish directly. The product manager's role has also changed: instead of drawing interfaces, they now dig up more business scenarios, translate them into technical language, and dispatch them to back-end developers to build Skills before publishing.
The results speak for themselves: Mado AI's weekly and monthly active users doubled, customers are not only active but also paying, and computing consumption exceeded expectations.
Gong Zhihao's metaphor is vivid: "Using Mado AI is like immediately having a 70–80 point operations director." — Especially for cross-border sellers in second- and third-tier cities, where it is hard to hire a good operations director, this is true technical democratization.
The product has changed, and the organization must evolve with it —
## How Does the Organization Evolve? Three Paths
### Talent Model: Specialist → Generalist + Specialist
Junior engineers use Qoder to fill in business understanding, while mid-level engineers can design complex systems. Cross-language capability becomes the norm — Mo Mingyi requires everyone to cross at least one language this year; Java developers must be able to use Python. "If you can't cross over, you need to give a reason, or it's hard to justify." This requirement would have been almost impossible two years ago. Now, with Qoder, environment errors are handled by AI, framework selection is handled by AI, and code is handled by AI.
### Organizational Structure: Pyramid → Networked Collaboration
Role boundaries are blurring. Product managers can produce demos, QA uses AI to accelerate, and the marketing team builds the official website itself. Everyone is "shifting left"; the chain is no longer one-way transmission, but integrated collaboration. Mo Mingyi made an analogy: if you don't use good tools well, you become the bottleneck in this team — not because you aren't working hard, but because everyone else is accelerating while you are running in place.
### Value Distribution: Hours-Driven → Value Creation
Performance is no longer measured by the number of requirements delivered, but by whether "AI-produced features quickly meet customer expectations." Incentives have also changed — hackathons have become business scenario entrepreneurship competitions, internal AI sharing sessions have been held every month for six consecutive months, and efficiency improvement projects only assess requirement delivery logic and AI usage. Value distribution has shifted from labor-intensive to intelligence-intensive.
### Advice for Those Still Watching
Mo Mingyi and Gong Zhihao gave practical advice from technical and operational perspectives — lessons from their own pitfalls.
● **Top-down initiative:** Only with top-level push can AI truly land. It cannot rely solely on individual interest. Eccang's strategy is company-wide certification, one account per person — start using it first.
● **Start with small, new projects:** Low risk, easy to deliver results, and builds confidence. Don't rush to refactor legacy projects all at once.
● **Make knowledge accumulation readable for AI:** In the past, documents were written for humans to read; now they are written for AI to read — use the same tool, the same language, and a format that makes it easier for AI to understand.
● **Develop a "driving sense":** Getting a license doesn't mean you can drive. Use it boldly and test narrow roads to find the boundaries. As Mo Mingyi said: "Maybe you start driving and end up flying, opening up an air route — that's possible too."
● **Avoid mismatched expectations:** AI is not all-powerful, nor is it something to give up on after two tries. Gong Zhihao has seen two extremes — one thinks AI can do everything for free, and the other gives up after two attempts. The right posture is to stay curious and first run through a small business scenario.
● **Standards first:** The technical engineering team establishes standards so that latercomers can calibrate their boundaries when interacting with AI through the standards. If you say "it can't handle this" after typing five words, that's not AI's problem.
● **Long-termism:** This is a sustained battle that requires patience. Be firm in strategy, flexible in tactics.
## Closing Words
Eccang's story is not a narrative of "AI replacing humans," but a story of how an organization, with Qoder, evolves from "tool users" to "agent managers."
From AI Coding across the entire R\&D team, to the "humanities professional productivity" of non-technical teams, to the intelligent agent factory model of Mado AI — Qoder is not playing the role of a code completion tool, but an engineering foundation that makes organizational knowledge explicit, capabilities reusable, and quality verifiable.
> After using Qoder, people who have been writing code for more than ten years find it easier and easier. — Mo Mingyi
*This article is based on the joint live broadcast by Eccang Technology and Alibaba Cloud, "Eccang × Qoder: AI Empowering Global Expansion."*
# 4M + 500K Lines, Rebuilding a Giant App in 3 Weeks
> How we shipped 500K lines into a 4M-line legacy system in three weeks using Agentic and Autonomous Engineering
## This Isn't a Greenfield Project
Earlier this year we published a case study: a five-person team shipped QoderWork in seven days using Qoder, work that would have taken twenty engineers several weeks the conventional way.
That story was a zero-to-one project — a clean codebase, our own rules, our own architecture, AI writing code onto a blank page with no historical baggage.
This article is the opposite story. This time the AI wasn't staring at a blank page. It was staring at a multi-year, multi-repo, multi-million-line production system.
The system we were upgrading is Qoder itself. Qoder is a real, running, complex system: the frontend is a VS Code IDE extension, the backend is a Go service handling agent orchestration, knowledge engine, and multi-model invocation system, and frontend and backend live in separate repos that together come to roughly four million lines of code. Architectural decisions from years past are scattered throughout the code. Implicit dependencies between modules have never been fully documented. Any sizable change can trigger a chain reaction.
On top of this system we needed to ship a brand-new 500K-line feature module — the full Quest overhaul that became Qoder V1.0:
- A redesigned standalone Quest view: directing AI like dispatching tasks, with a completely reworked interaction model
- A fully refreshed Editor: a systematic upgrade of the coding experience
- A knowledge engine: code distilled into knowledge, memory extracted from conversations, agents that get smarter the more you use them
- Multi-workspace, multi-task parallelism: cross-project coordination, multiple tasks delivered in parallel
- Experts Mode collaboration plus custom experts: parallel division of labor, flexible configuration
Delivery deadline: three weeks.
We used Qoder to build Qoder, and along the way we worked out a methodology specifically tuned for legacy giants — a combination of Agentic Engineering and Autonomous Engineering. What follows is the full account.

## Foundation First: Letting AI Actually Read Four Million Lines
The first obstacle to bringing AI into a legacy system isn't that the AI isn't smart enough. It's that the AI has no idea what has happened inside that system.
LLM context windows are bounded; you cannot stuff four million lines into them. The harder problem is that even if you could, the AI wouldn't know which lines are load-bearing architectural conventions, which are historical compromises someone made under deadline pressure, and which interfaces look refactorable but actually have a dozen callers depending on them.
An AI that knows nothing about the legacy system writes new code that reads as foreign material — inconsistent style, incompatible interfaces, quietly violating a handful of unwritten rules, then exploding during integration.
Our answer was to build out the AI's cognitive infrastructure before writing a single line of code. Three layers in total. The first two come from Qoder's product capabilities — Repo Wiki for the macro architectural view, the code knowledge graph for precise call relationships. The third is something we added through engineering discipline: keeping the spec and decision text of every major change checked into the repo, so the AI can not only see what the system looks like now, but trace why it became that way. Building Qoder with Qoder gave us the chance to build all three layers out fully.
### Layer 1: Repo Wiki (Qoder built-in)
A repository-level document auto-generated from the code and updated alongside code changes. It covers overall project architecture, module boundaries, core data flows, and the cross-module reference graph. It takes the structural relationships scattered across four million lines and consolidates them into a project document you can actually read end-to-end. Code by itself can tell you what an individual file does, but it can't tell you how the system is organized as a whole. Repo Wiki fills in exactly that panoramic view.
Repo Wiki is, in effect, a project map for the AI. A new AI agent doesn't need to crawl files one by one to reconstruct system structure. It reads the map and gets oriented immediately — how modules are partitioned, how dependencies flow, where the critical paths run.
### Layer 2: Code Knowledge Graph (Qoder built-in)
Through static analysis combined with AI-driven understanding, the entire codebase is structurally modeled: module dependencies, interface contracts, data flow direction, read/write paths of core data structures. This isn't a simple call graph — it's a queryable knowledge base.
When the AI generates new code, it can query in real time: "Who currently calls this interface?" "Where is this data structure mutated?" "If the new Quest view reuses this component, which existing features will it affect?"
Repo Wiki shows the AI the rough shape of the project. The knowledge graph lets the AI look up the exact call situation of any given interface. One coarse, one fine — the two faces Qoder ships with.
### Layer 3: Historical Spec Archive (accumulated engineering practice)
The first two layers come from Qoder's product capabilities. They let the AI see what the system looks like today. But there's still a missing layer — how this architecture evolved into its present shape. Why a particular interface was deprecated, what production incident a seemingly redundant compatibility shim was responding to — those decision trails usually live only in the memory of the people who were there. Once those people leave, the trail is gone, and the next refactor has to reverse-engineer intent from code, stepping into the same pits all over again.
This layer isn't something a product feature can hand you directly. You have to deposit it through engineering discipline. We keep the spec and decision text of every major change checked into the repo. When the AI fixes a bug or adds a feature, it doesn't just see what the code looks like now — it can reach back and ask why it became this way. The repo stops being a snapshot of current code and becomes a queryable engineering archive.
Two layers of product capability plus one layer of engineering practice — that's the foundation. Skip any of them and the AI is building on sand.
## Ultra Spec: Write the Spec Through Before Writing Code
With the foundation laid, we did not rush to code. The first move in the QoderWork sprint was already "write specs, not code." Inside a legacy system, this principle has to be enforced even more strictly — once the AI starts generating code, the cost of correcting course rises sharply. We call this stage Ultra Spec.
A regular spec describes what a feature is. An Ultra Spec describes every dimension of that feature, precise enough that the AI can implement directly from it, surfacing every issue that would otherwise cause rework. It has a fixed set of dimensions: functional goals, I/O contracts, business rules, edge cases, security boundaries, and a test plan. Each dimension has to be machine-readable — I/O is JSON Schema, not prose; every business rule maps to concrete inputs and outputs; security boundaries are split into three tiers: must-do, ask-first, must-not.
In a legacy system, every dimension also has to carry a "legacy lens." Functional goals must call out which existing modules are affected. I/O contracts must align with existing interfaces and explicitly preserve forward compatibility. Business rules must surface the implicit conventions of the legacy system — never let the AI guess. Edge cases must cover dirty historical data. Security boundaries must list off-limits regions of code. The test plan must include regression coverage for legacy functionality. Without this lens, what the AI produces is foreign material.
Take the knowledge engine module. Its spec is not just the sentence "extract memory from conversations." It precisely defines: what kinds of conversations get extracted, when the extraction triggers, the storage and retrieval structure for memory, the interface contract with the existing code indexing system, the degradation strategy when the memory store grows too large, and the isolation boundary rules between memories of different workspaces. Every line has concrete I/O. "It depends" is not allowed.
Finishing the spec isn't the finish line. From there it enters multi-agent cross-review. We launch several sub-agents with different perspectives to audit the same spec independently: an architect agent checks module boundaries and interface design, a security agent looks for permission holes and data leakage, a performance agent predicts slow queries and high-frequency call bottlenecks, a legacy-system agent (backed by the knowledge graph) checks compatibility with existing code. After that comes a verification pass: an independent verifier agent reverse-derives every flagged defect to weed out hallucinated false positives. Final authorization is human — focused on the parts that touch SLO definitions and irreversible operations.
The time invested at the Ultra Spec stage is leveraged. A day spent here saves several days of debugging and rework downstream.
## Experts Mode: Turning the Spec Into Parallel Engineering
Ultra Spec breaks a module's requirements into a structured plan with clean dependencies. But there's still one gap on the way to delivery. A single module like the knowledge engine or multi-workspace parallelism spans the frontend IDE extension, the Go backend, agent orchestration, and the model invocation chain — thousands to tens of thousands of lines of change. If a single agent threads it end-to-end, the parallel branches Ultra Spec worked so hard to identify get serialized again. Worse, attention dilutes over long contexts and the conventions established early in the run quietly drift in the back half. Earlier versions of Qoder hit exactly this awkwardness: an agent task would clearly "forget" its opening as it neared the end.
Experts Mode is built to close that gap. It's a Team Lead plus a set of specialist agents. The Team Lead doesn't write code. It reads the Ultra Spec task list, identifies dependencies, and dispatches work in DAG order to backend, frontend, testing, review, and research specialists. Each specialist runs in its own context, so they don't crowd each other out. The substantive difference between this and "just open several agent windows at once" is coordination: those windows have none. Experts Mode translates the DAG that Ultra Spec already identified directly into an execution plan, so frontend and backend can advance simultaneously. When ambiguous choices come up mid-execution — which encryption algorithm, whether the compatibility strategy should degrade or fail loudly — the Team Lead surfaces the candidates for a human decision before dispatching, instead of letting the AI guess in silence.
Experts Mode also doesn't force every specialist to use the same top-tier model. Lightweight roles like researchers and bootstrap engineers run on cheaper, faster models. Architecture-critical reviewers and complex refactor engineers run on flagship models. The blended cost lands at one-half to one-fifth of running flagship-everywhere, while the intelligence floor on the critical path doesn't drop. Across three weeks we ran hundreds to thousands of sub-tasks. Putting every one of them on the most expensive model would have blown the budget; putting all of them on the cheapest would have left quality unguarded at critical nodes. Heterogeneous scheduling sits exactly on that budget curve.
Experts Mode also retains what the team has learned. Each specialist accumulates an Expert Skill (how to spin up the test environment for a given module, the historical pitfalls of a given interface). At the team level, a Team Skill accumulates (which dispatch pattern works best for which class of task). The next time a similar workload comes through, this experience plugs straight in.
## Ultra Review: Surfacing the Details Inside AI-Written Code
A new bottleneck shows up immediately: AI generates code far faster than humans review it.
Qoder runs many Quests in parallel — knowledge engine, multi-workspace parallelism, Experts Mode collaboration — all advancing at the same time, each module potentially producing thousands of lines of code per day. If review stays linear and single-threaded, it instantly becomes the chokepoint of the whole pipeline, and however fast the AI runs, the gain is canceled out.
Our answer is Ultra Review: turn code review from single-threaded into multi-agent parallel.
Concretely, every PR gets a group of agents reviewing it in parallel. They start scanning from different positions in the code, with different traversal paths and different context loading orders. The point is to counteract the LLM's context-window bias — a single agent reading top-to-bottom tends to "thin out" its attention in the back half and miss problems. After the parallel pass comes verify and dedup: weed out hallucinated false positives, merge duplicate findings where multiple agents flagged the same issue.
Review concentrates on a handful of dimensions: correctness, security, performance, architectural consistency, maintainability. Architectural consistency matters disproportionately on this project — 500K lines of new code that drift away from the legacy system's architectural style will compound technical debt exponentially. Every piece of AI-generated code gets checked: does the naming match legacy conventions? Does the layering match existing modules? Does it bypass the legacy abstraction layer to manipulate internals directly?
Ultra Review has one rule: chase logic errors, ignore style. Style goes to linters and formatters. AI's review compute stays on what actually matters.
## Computer Use Validation: AI Grows Eyes and Hands
Once the code is written and review is clean, you still have to verify the feature actually works.
Traditional automated testing has a structural problem: writing the test scripts is itself a large chunk of work, the scripts usually only cover the happy path, edge cases need separate authoring, and maintenance cost grows linearly with code volume.
Computer Use changes the framing.
Qoder takes over the local development environment directly — screenshotting, locating coordinates, simulating keyboard and mouse — operating like a real person. You don't write test scripts. You describe the behavior to verify, and the AI handles the rest:
1. Spin up the IDE and confirm code state
2. Run the project and wait for services to come up
3. Open browser or IDE surfaces and execute the full business flow
4. Verify results against the expected outputs defined in the spec
5. Cover edge cases: empty inputs, permission boundaries, concurrent scenarios, legacy data compatibility
Take multi-workspace parallelism. Validation isn't "can it open multiple workspaces." It's: when two workspaces run agent tasks simultaneously, do they contend for resources? When you switch workspaces, is context correctly isolated? Does the knowledge engine's memory preserve the right isolation boundary across workspaces?
When something breaks, the AI walks the full triage flow on its own: it assembles the operation trace and screenshots, parses error logs, hands in an initial root-cause hypothesis, and files a GitHub issue directly through the API. The issue isn't a bare "feature broken" — it includes reproduction steps, error context, and a first-pass code location.
This loop covers three trigger paths: proactive validation after a new feature lands, automatic invocation in the CI pipeline, and automatic invocation when log monitoring catches anomalies in production.
## Nightly Auto-Heal: Letting Machines Work While You Sleep
At this section the shape of the methodology shifts. Until now, AI has been a collaborator with a human in the loop — that's Agentic Engineering. Nightly Auto-Heal removes the human from the loop and lets the machine run the discover-fix-verify cycle on its own. This is where Autonomous Engineering begins.
Issues from validation runs, manual testing, CI failures, and production log alerts all flow into a single processing queue.
After the team logs off, Nightly Auto-Heal kicks in automatically.
```
Issue enters queue
↓
Model performs root-cause analysis using the code knowledge graph
Locates relevant files and call paths
↓
Generates a fix plan plus a corresponding spec patch
↓
AI executes the fix and opens a PR
↓
Computer Use runs self-validation
(full business flow + edge cases)
↓
Pass ──→ PR ready, awaiting human review and merge
Fail ──→ Flagged for human triage, prioritized for the morning
```
The point of this loop isn't "full automation." The point is to redistribute human time.
When engineers come in the next morning, simple bugs in the queue already have PRs waiting for review. Root-cause analysis is done. The fix has already passed self-validation. Engineers don't start from scratch — they make the final judgment call.
Engineers stop being pinned to the chain of "find the bug, locate the code, write the fix, verify by hand." That time gets redirected to where human judgment is actually required: architectural decisions, complex root-cause analysis, the final go/no-go before merge.
The pairing of Nightly Auto-Heal and the code knowledge graph is where the leverage shows up most clearly. The most expensive part of bug fixing has rarely been "writing the patch" — it's been "finding the problem." Locating a bug across four million lines of code can take hours. The knowledge graph lets the AI trace call chains fast, compressing localization from hours to minutes.
## Three Weeks Later
Three weeks. 500K lines of new code. 99% AI-generated.
Quest standalone view, knowledge engine, multi-workspace parallelism, Experts Mode collaboration — all of it landed in Qoder V1.0 and shipped to users.
But the number isn't really what this article is about.
What sits behind the number is that we've now run two methodologies that lock into each other end-to-end: Agentic Engineering, where AI collaborates at high quality under human supervision, and Autonomous Engineering, where machines keep running the loop after the human has logged off.
The difference between a legacy giant and a blank-slate project is cognitive load. On a blank-slate project the AI can improvise. In a legacy system the AI has to be domesticated first — it has to know what this system has been through, what has been agreed on, and what cannot be touched.
The five-layer structure of this methodology maps to five distinct functions:
| Layer | Tooling | Function |
| ---------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| Foundation | Repo Wiki + Code Knowledge Graph + Historical Spec Deposits | Lets AI understand both the current state and the evolution of 4M lines of legacy code |
| Leverage | Ultra Spec + Multi-Agent Cross-Review | Surfaces rework-causing issues before any code is written |
| Execution | Experts Mode (Team Lead + specialist agents + engineering knowledge engine) | Turns the spec's dependency graph into parallel engineering delivery |
| Guardrail | Ultra Review (multi-agent parallel) | Keeps up with AI's generation speed and catches the details inside the code |
| Flywheel | Computer Use validation + Nightly Auto-Heal | Closes the discover-fix-verify loop into an autonomous cycle |
None of the five layers is optional. Ultra Spec without the knowledge graph misses the legacy system's implicit constraints. Experts Mode without Ultra Review lets parallel specialists silently drift apart on style and boundaries. Auto-Heal without Ultra Review produces an endless stream of new bugs to fix because code quality wasn't held at the source.
One more thing worth saying: the engineer's role changes in both stages, but in different ways.
In the Agentic stage, the engineer is the standards-setter — defining the precision of the spec, drawing the architectural lines, deciding which review perspectives are mandatory, and making the final call on whether a PR merges. The AI writes code, the human sets direction.
In the Autonomous stage, the engineer co-designs the verification system with the AI. For the machine to keep running the loop after the human has stepped away, it has to be able to judge "is this right?" on its own. That trustworthy verification infrastructure isn't something a human writes alone: end-to-end Computer Use validation, unit tests, integration tests, the CI pipeline, production log monitoring, regression datasets — every layer is hammered out jointly. The human defines what "correct" means and the fallback logic; the AI translates that definition into executable checks. The more solid the verification system, the wider the radius the machine can autonomously cover.
How far AI can go is a function of how solid the cognitive infrastructure and verification infrastructure you give it are. The more precise the spec, the less the AI deviates. The more complete the verification, the more the flywheel actually spins.
AI doesn't replace engineers, because the scarce resource in this game has never been the ability to write code. It's the ability to define what counts as correct. The Agentic stage defines the precision of the spec; the Autonomous stage defines the boundary of verification. AI can't help you with either of those, but those are the two things that decide how big a radius AI can work in on your behalf.
Writing code is becoming infrastructure rather than the engineer's core job. The real moat has moved upstream — to whether you can break a fuzzy requirement into a spec a machine can execute, and whether you can translate "this looks fine to me" into criteria that can be auto-verified. The better you do those two, the further AI runs and the larger the engineer's leverage.
# R&D Efficiency Evolved: How UU Paotui Deeply Integrated AI into the Entire Development Lifecycle
> UU Paotui leveraged Qoder's Wiki + Rules + Skills to transform AI from an "outsider" into a full-lifecycle teammate.
Hi everyone, I'm Yuan Zhao, Head of Engineering at UU Paotui. Today I'll share how we embedded AI into every stage of our development workflow.
## I. Why UU Paotui Needed AI Across the Full Development Lifecycle
### Technical Background
As a leading on-demand delivery platform, we process millions of orders daily. Our tech stack is a typical microservices architecture with over 800 core services, spanning frontend, backend, and big data. Balancing development velocity with code quality in such a massive, complex system has always been our core challenge.
As AI coding tools became widespread, new problems emerged: AI-generated code was fast but stylistically inconsistent, actually increasing code review overhead. More critically, AI didn't understand our complex business logic or microservices architecture—generated code often required heavy modifications before it was usable.
We identified four core pain points:
- Knowledge lived in people's heads—impossible to effectively preserve or transfer.
- Our coding standards existed only on paper—enforcement was inconsistent.
- Design patterns couldn't be reused—resulting in redundant work.
- AI tools felt more like an "outsider" that constantly needed correction, rather than a trusted teammate.
Together, these bottlenecked our engineering productivity.
## II. A New Paradigm: From "AI-Assisted Coding" to "AI-Embedded Workflow"
Facing these pain points, our core philosophy shifted. We stopped treating AI as merely a coding assistant and committed to making it a first-class participant in our development process. This meant AI needed to understand our business context, embed standards into its generation process, retrieve our accumulated knowledge, and ultimately unify design, coding, and review into a single intelligent flow.
Our solution: restructure the entire development workflow on the Qoder platform. We built a knowledge foundation centered on enterprise-level Repo Wiki, then layered on a standards tier (Rules), a design tier, and a quality tier (Skills). With this architecture, AI learns our knowledge, standards, and design patterns before generating a single line of code—ensuring quality and business alignment from the source.
## III. Workflow Transformation in Practice
### Practice 1: Teaching AI to "Speak Our Language"
The goal: every line of AI-generated code complies with our enterprise coding standards.
We distilled our standards, encoded them as Qoder Rules, and integrated them into the AI generation process—achieving "compliant by default."
Result: first-pass compliance rate jumped from 60% to 95%.
### Practice 2: AI-Powered Code Review
We designed an intelligent Code Review Skill in Qoder. It can be triggered via Merge Request or conversation, reviewing code across multiple dimensions—coding standards, potential bugs, performance, and security—then outputting a detailed report. This dramatically reduced the manual review burden.
Through standardized tagging and automated pipelines, engineers are freed from tedious release operations to focus on delivering business value, while ensuring release safety and consistency.
### Practice 3: Giving AI Full System Awareness
The fundamental problem: AI didn't understand our complex architecture. Our approach—first teach AI the system, then let it participate in design.
Step one was knowledge capture. Using Qoder, we parsed existing microservices and auto-generated application-level Wiki documentation. With Qoder Quest Mode, the complete development cycle for a feature takes only 3 hours: 1.5 hours writing specs, 30 minutes of AI generation, minutes-level Code Review, and 30 minutes of code refinement. A massive efficiency gain.
We also exposed APIs as MCP endpoints covering our city-level backend, building a standardized interaction hub between AI Agents and business systems.
In the traditional workflow, AI only provided fragmented assistance during coding. In our new workflow, AI is deeply embedded in design, generation, and review—every stage built on our knowledge foundation and standards. The efficiency leap is qualitative.
Key insight: we don't manually write complex documentation anymore. All Wiki, Rules, and Skills are AI-generated. As long as we feed in the right enterprise context, AI outputs exactly what we need.
- **Project Kickoff:** Import PRD into the knowledge base, generate high-level design.
- **Detailed Design:** Generate detailed specs based on the high-level design and existing code.
- **Coding:** Develop under Rule constraints.
- **Review:** Automated Code Review via Skills.
- **Testing & Release:** AI generates unit tests and functional test cases (70%-80% adoption rate), then one-command release via CLI.
Our biggest takeaway: successful AI adoption requires "governance first." Ungoverned AI only creates tech debt. Knowledge capture is the foundation for AI to understand your business. Process design matters far more than simply adopting tools. We must treat AI as an inherent part of the development workflow and advance it with a continuous iteration mindset.
## IV. The Future of This New Paradigm
Looking ahead, we see enormous untapped potential. We're exploring:
- **Intelligent Testing:** Beyond unit and functional tests, focusing on UI automation and business-log-based vulnerability diagnosis.
- **MCP Scenarios:** Packaging admin capabilities into standardized interfaces and MCP endpoints—democratizing development so business teams can build custom plugins to boost personal productivity.
- **End-to-End Automation:** As model capabilities advance, further optimizing workflows toward true end-to-end intelligent delivery.
We believe AI will play an increasingly vital role in our engineering work.
# From Line-by-Line Coding to 2-Minute Delivery: How Fuiou Payment Turned Hard-Won Lessons into Team Capability
> Six months with Qoder across 12+ projects — I stopped writing code and started directing AI.
I'm E Jian (鄂建), a senior developer at Fuiou Payment. Running Qoder across a dozen projects for over six months, my entire workflow transformed — from writing code line by line to setting direction, feeding context, and validating results.
The shift didn't happen overnight. Like most teams, we went through the full arc: install the tool → think it's decent → hit a wall of pitfalls → eventually forge a methodology. Today I'll break down that journey.
## The First Insight: AI Output Quality = Your Context Quality
This is the first iron rule we discovered. Sounds obvious, but most teams stumble right here.
"There's a bug in this code, fix it for me." — That's the most common prompt I've seen, and the most useless one. If you said that to the colleague sitting next to you, they wouldn't know what you meant either — let alone an AI.
The right approach: tell the AI `@OrderService.java` line 156 throws a NullPointerException, triggered when order status is null. Exact location, symptom, relevant files — all three are non-negotiable.
This insight sounds simple, but embedding it into team habits took us considerable time.
## Phase One: Building the Fundamentals
### From "Typing Off the Cuff" to "Structured Input"
I built a habit: never type complex requirements directly in the chat box. The box is too narrow — after a hundred words you can't see the full picture, and your train of thought breaks with it.
My approach: open a notepad first, organize the full requirement description with placeholders, then paste the whole thing into Qoder and @ relevant files at the end. Structured input looks like this:
```plaintext
Goal: Implement order export
Constraints: Stream-write 5M+ records
Reference: @ExportService.java existing export logic
```
Three lines. Not a 200-word essay leaving the AI to guess what matters.
The strategy is clear: **skeleton first, details later**. Give the goal and constraints in round one; after AI outputs, add targeted refinements. Converge within three rounds. Qoder also has a "Prompt Enhancement" button in the lower right — click it after writing and AI optimizes your expression structure. Poor input quality guarantees poor output quality.
### A Prompt Trick: Making AI "Post-Mortem" Your Project
Here's a method I frequently use in exploratory projects — ask the AI to assume the project has already failed, then answer: When did things first go wrong? Which key decision went off track? Which risk should have been identified earliest but was overlooked?
I also add: "Explain it in a way that a retired farmer growing vegetables would understand."
The AI doesn't know your technical level, but it knows what level "a farmer growing vegetables" is. The output becomes as plain as possible — no smokescreen of jargon.
The real purpose of this prompt is to force AI into an end-state perspective to surface risks early. In one e-commerce project, this method helped us identify a performance bottleneck in high-concurrency scenarios ahead of time. We introduced an async queue design and avoided a post-launch crash.
### Context Pollution: Tuition We Paid
The most frequent pitfall in our early days was "context pollution." The typical path: Round 1 — AI proposes a flawed fix for a NullPointerException. Round 2 — you continue building on the flawed approach. Round 3 — you point out the problem. Round 4 — AI loops back to the Round 1 assumption. Dead loop.
We distilled one hard rule: **If the same issue hasn't converged after 3 iterations, start a new chat window immediately.** Don't mourn the previous conversation — a clean context costs ten times less than repeatedly correcting a polluted one.
Same principle: don't @ seven or eight files at once. One file runs 600–1000 lines; seven or eight fills over 10,000 lines, maxing out a 200K context window. Once compression kicks in, AI drifts. Give only the necessary context per conversation; never mix unrelated topics.
### Models and Modes: Stronger Isn't Always Better
After a while, we found that matching different tasks to different models and modes makes a dramatic difference:
Architecture design → Ultimate model. Bug fixes → Performance model. Daily coding → Auto. As for coding modes: **Editor** = you drive, AI navigates; **Quest** = you name the destination, AI confirms then plans the route; **Expert Panel** = you've hired a dev squad.
But consumption differences are real: Quest and Expert Panel cost roughly 8× what Editor does. Don't casually fire up Expert Panel for routine coding — you can burn through 2,000 Credits in a day or two.
## Phase Two: From "Knowing How to Use It" to "Configuring the Environment"
Once the fundamentals were solid, the bottleneck shifted. It was no longer "how to talk to AI" but "how to let AI work autonomously within my project environment."
### Giving AI External Capabilities: MCP
MCP (Model Context Protocol) is the key to breaking AI beyond local file boundaries. Without it, AI can only read what you @. With it, AI can search the web, query databases, operate browsers, and call external systems.
But the configuration principle is **less is more**: keep it under 8. Each MCP's tool descriptions are loaded in full into the context — too many and you blow it up. Enable and disable based on actual need.
### Direct Database Connection: AI Queries and Validates on Its Own
Previously, debugging a bug meant manually copying table schemas, pasting them to AI, getting a solution, then manually adjusting. Shuttling data back and forth ate up most of the time.
Now, just @ the database connection directly in the IDE chat. AI reads the schema and generates Entity, Repository, and Controller — field names, types, and constraints all correctly mapped.
More critically for troubleshooting — AI reads code logic while simultaneously querying the database to verify data, directly determining whether it's a code issue or a data issue. No more acting as the middleman shuttling information; it queries and judges on its own.
### SSH Remote Debugging: From Constant Back-and-Forth to One Shot
Traditional flow: SSH into server → manually check logs → copy content → switch to AI → describe the problem → AI guesses an answer → go back to server to verify. A minor issue could eat one or two hours.
Now AI connects directly to the server, reads logs and configs in real time, and delivers targeted solutions in one step.
Of course, security principles are non-negotiable — least-privilege accounts, manual confirmation for high-risk commands, caution in production environments, and complete operation logging.
### Hooks: Managing AI with Aspect-Oriented Thinking
I compare Hooks to aspects in Java — before-advice and after-advice.
Why do we need them? Real pitfalls our team has hit: accidentally pasted `access_key=AKIA...` into a prompt and sent it to the model without thinking; AI wanted to execute `rm -rf /data/`, we clicked confirm, and several GB of data vanished; AI said "done," but running tests revealed nothing but compile errors.
Hooks solve three problems: intercept sensitive information before submission, automatically run compilation verification after execution, and persist changes to external systems after response. Configuration is committed to Git — the entire team shares the same safety net.
### Rules Configuration: Lessons from a Dozen Projects
We currently have over a dozen projects running on Qoder, and rules configuration is paramount. Different projects call for different strategies:
New projects directly reuse general rule templates (java.md, code.md, etc.). Iterative projects first generate a RepoWiki, letting AI summarize a draft based on existing code style, then manually review and fine-tune. Multi-subproject repos place an AGENTS.md at root as a navigation map.
The configuration principle boils down to one line: **Too many rules equals no rules.** Keep each file under 200 lines. Start with core rules, continuously update based on conversation feedback, and boldly delete when redundant.
### Memory System: Making AI Understand You Better Over Time
Memory records user preferences, tech stack, naming conventions, and historical pitfalls. Management uses a lazy-loading strategy — load on demand, never send everything every conversation. Keep global memories limited in quantity and periodically clean out outdated content.
The core value is the compounding effect: the longer you use it, the better AI understands your project, and the lower the probability of repeating the same mistakes.
## Phase Three: Landing a Refund Feature in 2 Minutes
Once fundamentals and environment configuration were both in place, the real inflection point arrived.
We adopted the OpenSpec (Spec-Driven Development) workflow — a four-step closed loop: **Explore → Proposal Design → Implement → Archive**. It's more stable than Plan mode: proposals persist in the project repo, so starting a new window or picking up the next day loses nothing.
A real example. I type "Help me develop an order refund feature":
**Exploration phase** — AI automatically searches the project structure, scans existing tables and interfaces, and maps out the current business state. **Clarification phase** — AI proactively asks: What's the refund scenario? Who can initiate? When is it allowed? Is approval required? **Proposal phase** — outputs three documents: a change proposal, a design doc, and a development task doc, all detailed down to field level. **Execution phase** — breaks it into 23 fine-grained tasks, generates refund entity classes, Mappers, DTOs, five endpoints, and one new table in roughly 2 minutes, modifying 24 files. **Archive phase** — once confirmed, archive it; next time a new window opens, AI automatically checks for unarchived tasks and continues.
This is why task decomposition matters so much — high-level direction is where mistakes happen, but broken down to field level, AI executes with precision.
## The Core Logic of Saving Credits
After six months, we distilled one counterintuitive pattern: **The leaner the context, the fewer Credits consumed, and the more accurate AI's output.**
This translates into several key actions: AGENTS.md stays under 100 lines (too long and AI actually stops following it); rules are categorized under `.qoder/rules` and loaded on demand rather than always active; generated RepoWiki must be manually trimmed — delete unused deployment plans; add `.qoderignore` to exclude build artifacts; require AI output summaries to stay under 100 words — we never read those long recaps anyway.
One more often-overlooked tip: use the LLM provider's official web interface for non-coding Q\&A — it's free, unlimited, and sometimes faster. Save your Credits for coding tasks that genuinely require project context.
## Final Thoughts
After half a year, my biggest takeaway: the developer's role is undergoing a fundamental shift.
We're no longer "the people who write code" — we're "the people who set direction, control quality, and make judgments." AI is responsible for doing things fast; human thinking is responsible for doing things right.
If I had to give a few pieces of advice to teams just starting with AI Coding: don't rush into complex configurations — master context management first; don't be afraid to start a new chat window; keep rules few and sharp, not abundant; commit frequently rather than in bulk — validate immediately after writing, and push to Git if it passes.
Tools will keep getting more powerful, but the methodology for mastering them won't go out of date.
*This article is based on the online talk "Qoder AI Best Practices" by E Jian (鄂建), Senior Developer at Fuiou Payment.*
# From "Expert Know-How" to "Team Capability": AsiaInfo's 3 Iron Rules for AI R&D Tool Selection
> This is the real transformation path that a mature ICT enterprise carved out over three years.
I'm Zhu Jun, Chief Architect at AsiaInfo Technologies.
AsiaInfo has been deeply rooted in the telecom industry for over three decades, with nearly 10,000 R\&D engineers. At this scale, "company-wide AI Coding" sounds more like a slogan than a goal — but this year, we actually pulled it off. From frontline engineers to architects, almost everyone is now collaborating with Agents in their daily work.
What I want to share isn't a polished slide deck. It's the real-world AI transformation path that a mature ICT enterprise navigated over three years.
## What Day-to-Day Used to Look Like at AsiaInfo
Telecom carriers' BSS (Business Support System) and OSS (Operations Support System) projects make up a significant share of AsiaInfo's business portfolio.
These IT systems share two defining traits:
● Extreme system complexity: from 2G to 5G, legacy services never get retired while new requirements keep flooding in — every change ripples through everything.
● Extreme knowledge accumulation: thirty years of engineering know-how, scattered across senior experts' minds, hundreds of out-of-sync documents, and millions of lines of legacy code.
A new hire used to spend two to three months just getting familiar with a single module.
Meanwhile, telecom carriers are pursuing business transformation — strengthening the core business while building out a second growth curve. That puts a hard "efficiency growth" demand on AsiaInfo as their service partner.
We had to use AI to reorganize the production relationships.
## Setting the Direction: AI Native Is Not a Slogan
After ChatGPT launched at the end of 2022, my team and I had a serious conversation about one question: what will future application software look like?
Our answer was: Cloud Native will inevitably evolve into AI Native.
The shift plays out across three layers:
● Infrastructure shifts: from container-centric PaaS to large-model-centric MaaS.
● Development paradigm shifts: from DevOps to AI Engineering — from humans writing code to humans steering Agents that write code.
● Application paradigm shifts: from SaaS to Agents, supported by three pillars — "business ontology knowledge + digital twin + intelligent agents."
Once the direction was clear, we baked "AI First" into every detail of how we work.
We started with "foundation model + RAG," feeding our own code and documents into the system. Then we brought in Qoder CN (formerly Tongyi Lingma) and Qoder. The capability boundary expanded from "code completion" step by step into requirements, design, testing, and bug fixing — gradually forming a complete R\&D team.
This journey crystallized into three iron rules I now use for tool selection:
● Look at sustained investment in the foundation model: is the company really pouring resources into software engineering, and is it iterating faster over time? This determines whether you're buying a car that can keep upgrading.
● Look at the surrounding ecosystem: it's not just the model — it has to fit your organization, processes, and standards, and be flexibly configurable.
● Look at the security foundation: a trustworthy model and a trustworthy runtime are the entry ticket for clients like telecom carriers.
## AsiaInfo Pulls 30 Years of Industry Experience Out of the Experts' Heads
The hardest part has never been writing code — it's preserving knowledge.
Senior experts' experience and decades-old code logic used to be passed down through one-on-one mentoring. That was inefficient, and it's becoming unsustainable. Once we brought Agents in, the problem became even more direct: silicon-based and carbon-based employees have to collaborate, which means the Agents also need to "understand" our systems.
Our approach is to truly structure the business ontology knowledge so it can be stored in a form that both humans and Agents can read and reach consensus on.
Qoder's knowledge engine made a real difference here. The key is not "yet another RAG," but:
● AI-driven extraction and maintenance: instead of relying on senior engineers to manually build the library, the engine automatically extracts standards, API assets, and architectural traits from the codebase, and turns daily conversations into knowledge cards.
● Knowledge-friendly format: long documents are split into small cards and paired with hybrid retrieval, so Agents can hit the right note as quickly as flipping through index cards.
● Repository-level sharing: when a senior expert deposits knowledge into a repo, the entire team can share it.
In one sentence: senior experts deposit knowledge, while new hires and Agents share and reuse it together.
## Breaking Down Complex Business and Letting a Swarm of Agents Run It in Parallel
There are no "small projects" in carrier systems. Take one carrier's healthcare project: front office, back office, billing, and customer service are all wired together end-to-end, spanning 31 provinces plus the group HQ.
In the past, this kind of system ran on a serial R\&D rhythm — touch one piece and you have to redo everything. The way we work now:
● Architects first define the overall boundaries, module breakdown, and interface contracts.
● Spec is used to write down constraints and roles — for example, "this Agent only handles localization, not code changes."
● Multiple Agents move forward in parallel, then everything is reassembled at the architecture layer.
We've polished this workflow most thoroughly in the deterministic scenario of bug fixing. Early on, we just dumped logs and user feedback at the AI, and accuracy was poor. Then we layered in constraints, expert experience, code context, architectural knowledge, role boundaries — and the success rate steadily climbed.
Human control over AI doesn't come from watching it. It comes from layering constraints and knowledge into the workflow.
## Developing Agents with Agents, Orchestrating Agents with Agents
The Qoder team's own sharing left a deep impression on me.
Their development cadence: in nine months, they shipped 60+ external releases and over 130 internal versions — averaging a new build every one to two days.
Why so fast? Because Qoder is built using Qoder:
● Product managers sketch prototypes, and design flows directly into code.
● New features are developed in Spec mode.
● Once a bug is filed, the environment and logs are automatically packaged and handed to an Agent, which reproduces, fixes, and verifies it on its own.
● Integration tests and regression tests — anything that can be handed to an Agent is handed over.
What humans keep is decision-making, steering, and continuous improvement.
This gave me an important insight — AsiaInfo is now building an "Internet of Agents": my Agent buys for me, your Agent sells for you, and behind it all sits a new layer of billing, protocols, and trust. It's an entirely new application paradigm, and only this kind of "self-developing-self" iteration speed can bring it to life.
We're shaping the corresponding product forms too. Qoder Wake, recently launched by the Qoder team, runs Agents on individual machines so that the bug-localization, bug-fixing, and final-testing Agents share context and coordinate with each other — that's the early form of a digital employee.
## AsiaInfo's Real Numbers on Digital Employees
When you talk about delivery, you can't avoid the numbers. We've always measured R\&D the way we run software engineering projects. After bringing in AI, all that changed was that we added one more dimension — "the contribution of digital employees."
● Coverage: BSS systems hit the highest coverage. OSS is slightly lower due to stronger deterministic constraints. Overall, around 80%.
● Activity: take the team serving one major carrier — 1,000+ registered engineers, with monthly active rate consistently above 90%.
● Code-level efficiency: per-engineer code output up by roughly 14.6%.
● End-to-end efficiency: across the full pipeline from requirements to testing, average uplift of 8.6%.
These aren't headline-grabbing numbers, but they're real. And every percentage point frees up significant headcount to work on innovation — that's the real value of bringing in AI.
## Three Pieces of Advice for Industry Peers
If your enterprise is considering bringing AI in, here are three pieces of advice:
● First, model selection sets the ceiling: the foundation model is the bedrock. Without sustained investment, it won't take you far.
● Second, manage Agents like new hires: you need to give them a role, set up the environment, define the boundaries, and run evaluations — not just "install a tool."
● Third, drive the flywheel with data: without data, you can't tell where to adapt your workflow when the next generation of models arrives.
## Final Words: AI-Era R\&D Is a New Kind of Partnership
There's a quote from Steve Jobs that has stayed with me — Technology Alone Is Not Enough.
AI Coding gives us an opening: to free people from repetitive labor, so they can focus on work with more taste and more creativity.
From here on, your collaborator isn't just a carbon-based colleague — it's also a group of digital partners evolving alongside you.
Together, we achieve more.
# A Photographer's Vibecoding Journey: 5 Months, 150,000 Lines of Code, Independently Delivering 3 Commercial-Grade Products Through Struggles and Breakthroughs
> A photographer wrote 150,000 lines of code with Qoder, independently delivering 3 commercial products in 5 months.
"This time last year, I still thought AI coding could only produce tool scripts for personal use—impossible to create a sellable product."
Youfeng, the Product Lead at Yueliu, has been working in the film and television industry for a decade. From cinematographer and colorist to technical producer, he has participated in countless projects, transitioned from user to product developer, and led the development of multiple products serving the film industry.
But one problem always troubled him: he had countless product ideas, yet the implementation process was always difficult and painful.
"I'm the product lead, but I completely depend on the team for coding. Sometimes a small feature takes weeks from requirement submission to launch. If I want to independently build something to validate an idea, there's simply no way to start quickly."
"The high cost of trial and error became the biggest constraint on product innovation."
## The Pre-Agent Era: Barely Adequate, But Not Truly Useful
It was early 2024, before the term "VibeCoding" even existed, when Youfeng first tried AI-assisted programming. He spent three days using ChatGPT through conversation to complete a small desktop application, achieving the expected functionality, but the experience left him somewhat frustrated.
"The feeling at the time was that it could make a demo, but it was far from a real commercial product. Code quality, architecture design, long-term maintenance—all were problems. So I didn't pursue it further."
## The Turning Point: Encountering the Agentic IDE
The real change happened in September 2025.
"I was drawn by the tagline on the official website: 'An agentic programming platform for real-world software.'"
"After getting in touch with Qoder, I clearly felt the difference. This wasn't 'I ask, you answer'—it could truly understand project context, handle complex system development, and help me make architectural decisions."
Youfeng began investing significant time in practice. The intense novelty kept him immersed day and night, and he still maintains over 50 hours of VibeCoding time per week—almost equivalent to a full-time developer's workload.
"VibeCoding is truly addictive, especially for someone like me with many long-suppressed product ideas. You constantly receive positive feedback from it."
## Typical Case: 72-Hour Rapid Delivery—MetaStills Pure VibeCoding Version Deployed on the Set of "Chang'an's Lychees"

One of Youfeng's proudest works is MetaStills—a still frame and metadata management tool for the film industry. But the true origin of this story lies in a specific scenario he observed among cinematographers.
"Cinematographers in their continuous creative work want to record, organize, and share highlight frames from their creations. In the industry, we typically use stills as the medium, but stills are different from ordinary photos—beyond the image itself, we also want to record and share the corresponding shooting metadata. There really lacked an effective tool for this."
It was a late night in May 2024. Youfeng was chatting with a friend. His friend's DIT team was creating daily shooting still reports for a well-known production. The traditional workflow was: DIT exports stills from color grading software → manually organizes metadata → layouts each image one by one → exports PDF to send to the director and cinematographer. The entire process took 3-4 hours every day.
"I thought at that moment: this could be completely automated. Although stills and metadata are distributed across multiple different software, as long as they're aggregated through standard interfaces into a dedicated still and metadata management software that can automatically extract, intelligently layout, and generate daily reports with one click—how much could efficiency improve?"
But the problem was: this had no relevance to the company's product ecosystem, and the development team had no resources to take on this new requirement. So Youfeng chose to collaborate with outsourced development to advance this product project, but the communication efficiency and delivery quality of outsourced collaboration always left him unsatisfied—until a year later—
"On the first day I installed Qoder, I realized: this time I could try it myself."
Youfeng opened Qoder and began his first "pure VibeCoding product build."
**Day 1: From Product Documentation to Running Prototype**
"I spent about 4 hours working with AI to reorganize a detailed Spec document. Product definition, user groups, core features, tech stack selection, even interface structure—all written in. Then I fed the Spec to AI and said: 'According to this, let's begin.'"
By the end of day one, a rough but usable prototype was running: it could import stills, import and manage metadata, auto-match, draw still frames, customize styles, and generate PDFs.
"That night I stared at the PDF on the screen, my hands were shaking. In just one short year, VibeCoding capabilities had become this terrifyingly powerful."
**Day 2: The First "Crash" and Recovery**
On day two, Youfeng wanted to add a feature—having AI automatically select the optimal layout based on still content. But problems came one after another.
"The interface AI wrote looked fine, no errors reported, but runtime response was always slow. I had AI add lots of debug logs before discovering it had added a bunch of fallback mechanisms trying to handle various edge cases. The result was increasingly complex code where bugs were completely 'caught' by fallback mechanisms, making them difficult to find."
Youfeng realized this was a classic trap of AI over-engineering.
"I stopped and told AI: 'Delete all fallbacks, let the problems surface.' Then we reorganized the feature flow from the source together, finding the real logic flaws. After fixing it, the code was actually cleaner."
This small episode led Youfeng to summarize an iron rule: No fallback design during development—let problems surface early, fail fast.
**Day 3: From "Runs" to "Usable"**
On day three, Youfeng sent the new version to his friend, starting internal team testing.
"The feedback was direct: 'The new version is obviously smoother and more beautiful than the previous version, with significantly improved stability and rendering performance—but there are some small issues when importing metadata; it failed to import Silverstack's metadata format.'"
Youfeng immediately adjusted direction. In the morning, he analyzed Silverstack's exchange file format with AI and fixed compatibility for multiple formats including Silverstack and DaVinci Resolve; in the afternoon, he even completely refactored the entire metadata feature, implementing a metadata matching system that could customize metadata exchange specifications. This iteration efficiency was something Youfeng had never experienced in his previous product work.
"Comparing the progress efficiency of those two days, my previous work felt like a complete waste of time."
72 hours after starting development, the brand-new pure VibeCoding version of MetaStills went into trial use on the set of "Chang'an's Lychees" (a Chinese film production).
## From Prototype to Product: Five Months of Continuous Iteration
Those 72 hours of intensity were just the beginning. Over the next five months, Youfeng maintained a stable high-frequency commit rate, continuously polishing MetaStills:
- Design System: Established a complete Color Token system and component library
- Image Processing: Implemented HEIC async saving, end-to-end color management, HDR support, letterbox detection, smart cropping
- Cloud Services: Integrated iCloud sync, StoreKit subscription management
- External Integration: Developed HTTP API service, implemented DaVinci plugin
- Localization: Completed full Chinese-English localization
73 commits, 30,000 lines of code.
That same year, MetaStills received the "Outstanding Technology Innovation Application of the Year" honor at the 2nd China Science and Technology Film Week.

## Five Months, One Person, 150,000 Lines of Code
MetaStills is just the tip of the iceberg of Youfeng's VibeCoding practice. During the same period, he was also advancing numerous other projects:
Kuguan (Cool Manager), Yueliu's film equipment inventory management system. When Youfeng took over, the system already had version 1.0, but feature implementation was still incomplete with heavy technical debt. Through AI collaboration, he completed architecture refactoring, permission system fixes, and AI feature integration. 203 commits, 60,000 lines of code.
DEMAZE, Yueliu's AI-native media asset management system, developed from 0 to 1, involving complex technologies like Tauri desktop client, Rust backend, distributed file node services, and FUSE filesystem mounting. 234 commits, 60,000 lines of code.
Just these three projects alone: 510 commits, approximately 150,000 lines of code.
"I was quite surprised by this number myself. But looking back, it averages out to about 20 commits per week—as long as you maintain the rhythm, the accumulation becomes substantial."
## Those "Crashes" and Breakthroughs
Youfeng's VibeCoding journey was not all smooth sailing.
He discovered that AI's context capability is essentially "depth rather than breadth"—it can precisely remember code implementation details, function signatures, variable naming; it can discover fine-grained correlations in variable passing paths and type definition locations at the code micro-level; it can maintain high consistency in naming conventions, code style, and API calling patterns.
Human advantage lies in "compressed breadth"—grasping the project's overall architecture, module relationships, data flow, making macro judgments like whether architecture is reasonable and whether technology choices are appropriate. This "fuzzy global sense" is exactly what AI lacks. "After finding this division of labor boundary, efficiency improved significantly."
Another breakthrough was DevOps. "Honestly, I didn't even know what Jenkins and K8s were for before. The Kuguan system has multiple environments like SIT and FAT. I just directly asked AI: 'I want to deploy to the SIT environment, what should I do?'"
AI told him what to do next, and he executed. When encountering errors, he would paste the error messages to AI, and AI would help locate problems and provide solutions. Under AI's guidance, he completed environment configuration (understanding the differences and purposes of SIT and FAT environments), Jenkins build task configuration, K8s Deployment and Service understanding, Docker configuration optimization, and more.
Youfeng also summarized AI collaboration strategies for different development phases:
"In the 0-to-1 phase, like MetaStills, the goal is to quickly validate core assumptions. Code style should be aggressive, concise, disposable. Explicitly tell AI: no fallback mechanisms needed, no backward compatibility needed, focus on core features and cut edge cases, clear skeleton takes priority over detailed flesh."
"In the continuous iteration phase, like Kuguan, the goal is stability, maintainability, extensibility. Code style should be robust and standardized. Requirements for AI change: consider backward compatibility but don't over-engineer, complete error handling, code refactoring and optimization, technical debt cleanup."
"Different phases require different things from AI."
## Youfeng Today
Today, Youfeng is simultaneously advancing multiple projects: two software products under Yueliu, his own independent products, and third-party collaboration products. All code is completed through AI collaboration.
"My mindset has completely changed. Before, when I had a product idea, my first reaction was 'How many development resources will this need, how long will it take to schedule?' Now my first reaction is 'Let me build it overnight to validate it first.' This feeling of greatly shortened path from idea to implementation is the most satisfying part."
## Advice for Other Product People
Youfeng's story might offer some inspiration to people with similar backgrounds:
You don't need to become a programmer first before you can start. "I started from zero, with no computer science background. VibeCoding's barrier to entry is much lower than traditional programming. The key is to start hands-on and learn through practice."
Treat AI as a "hands-on teaching mentor." "Ask when you don't understand, paste error messages to it. It's so much more efficient than reading documentation or searching Stack Overflow."
Find the division of labor boundary between humans and AI. "Don't compete with AI on remembering details, and don't let AI make architectural decisions for you. Each plays to their strengths—that's when collaboration efficiency is highest."
"A year ago, I thought AI programming was a toy. Now I can't live without it. Not because it replaced me, but because it finally enabled me to independently complete those product ideas I've longed for so long."
—Youfeng, Product Lead at Yueliu, Independent Developer
# 5 People, 7 Days Creating a Miracle: The True Story of How the Qoder Team "Hacked" a Product with AI
> No product manager writing PRD, no frontend/backend division—the true story of how the Qoder team "hacked" a product with AI.
**Introduction:** No product manager writing PRD, no frontend/backend division—5 people completed in 7 days what traditionally takes 15-20 people several weeks. This isn't science fiction; this is the true experience of the Qoder team developing QoderWork with Quest.
## Customer Background
The Qoder team is a pioneer in the AI programming tools space, with multi-platform products including Qoder IDE, Qoder for VS Code, and Qoder CLI. In early 2026, the team decided to develop a desktop AI assistant for all users—QoderWork—to democratize Coding Agent capabilities for everyone.
## The Impossible Mission
**Challenges:**
- Traditional software development cycles are long, typically taking months from requirements to launch
- Complex role divisions (product manager, frontend, backend, testing, UED) result in high communication costs
- Need to rapidly validate a new software R\&D paradigm for the AI era
**Goals:**
- 5-person team to complete QoderWork development and launch from 0 to 1 in 7 days
- Explore a "role-less division" collaboration model
- Validate the new paradigm of "Spec-driven development"
## Solution: Not Writing a Single Line of Code, "Hacking" the Entire Product
### Day 1: Co-creation Defining Boundaries, Not a Single Line of Code Written

The team gathered everyone in the project room and used whiteboard co-creation to determine:
- MVP product boundaries: what to include and what not to include in the first version
- Module breakdown: functional descriptions, technical conventions, interface definitions, acceptance criteria
- Establishing technical architecture based on existing code assets
**Key Decision:** No traditional PRD documents; directly output technical Specs.
### From Day 2: Entering "Hack Code" Mode
The team adopted Qoder Quest's Spec-driven development model:
**Human-AI Co-created Specs:**
- Technical personnel describe requirements and intent
- Quest AI understands and asks clarifying questions (e.g., "Local or cloud database?" "Expected TPS?")
- After several rounds of interaction, human and AI jointly produce detailed Spec documents
**AI End-to-End Development:**
- Hand Specs to Quest; AI generates functional modules end-to-end
- Frontend architects build the skeleton; all engineers vertically own modules end-to-end
- UED directly produces frontend component code that meets engineering standards
### Parallel Development: One Person Directing Multiple AI Colleagues
**Early Phase (Shared Code):** One person per Quest, rapid iteration, frequent commits to resolve conflicts
**Late Phase (Vertical Modules):** One person with multiple Quests in parallel, isolating tasks through Git Worktree to significantly boost individual output
### AI Code Review: 7×24 Quality Gatekeeper
- All PRs automatically trigger Qoder CLI's AI Code Review
- AI understands existing codebase logic and proposes rigorous review comments
- Unresolved Review issues block code merge
## Results: We Did It
| Metric | Traditional Model | Qoder Quest Model |
| ------------------ | ---------------------------------- | ---------------------------------------- |
| Team Size | 15-20 people | 5 people |
| Development Cycle | 4-8 weeks | 7 days |
| Role Division | Clear frontend/backend/testing/UED | No role division; all Spec engineers |
| Communication Cost | Multiple rounds of document review | Sit together, align once |
| Efficiency Gain | Baseline | 60-70% end-to-end efficiency improvement |
**Launch Results:**
- January 30, 2026: QoderWork officially launched
- Supports both macOS and Windows platforms
- Core capabilities: autonomous task planning, local file operations, Skill system, privacy and security
## Core Discovery: Spec Is Your Productivity
> "In the future, writing code will increasingly be done by AI; humans clarify requirements and intent with AI through Specs."
> Not just AI-assisted coding, but AI driving the complete R\&D process
> — QoderWork Project Lead
**Traditional R\&D Process vs Spec-Driven Development:**
```plaintext
Traditional: PM writes PRD → Dev writes technical design → Development → Testing writes cases → Acceptance
Spec-Driven: Human-AI co-create Spec → AI end-to-end development → AI self-testing → AI Code Review → Human acceptance
```
**Key Transformations:**
- From "Software Engineering" to "Software Intentioning" (intent engineering)
- Human role upgrades from "writing code" to "system architecture design + requirements definition + quality review"
- AI becomes a tireless 7×24 "invisible team member"
## Customer Testimonials
### Project Lead Evaluation
> "We completed with 5 people in 7 days what traditionally takes 15-20 people several weeks. This is not just an efficiency improvement, but a revolution in the software R\&D paradigm. Quest is not a simple code generation tool, but an AI colleague that can understand intent, ask clarifying questions, and deliver end-to-end."
### Team Practice Insights
1. **Spec is the lifeline of quality** — Carefully reviewing Specs early to ensure AI understands correctly costs much less than rework later
2. **Task granularity** — One Quest corresponds to one testable functional unit for easy acceptance
3. **Don't skimp on Review** — Humans focus on architecture and logic; AI focuses on details
4. **Think AI first** — When encountering any problem, first consider if AI can solve it; cultivate an AI-first mindset
## About QoderWork
QoderWork is a desktop AI assistant launched by the Qoder team, based on Qoder CLI's Coding Agent capabilities, enabling non-programmer users to enjoy the convenience brought by AI.
**Core Capabilities:**
- 🎯 Autonomous Task Planning: Understand intent, break down steps, execute automatically
- 📁 Local File Operations: Process office documents like PDF, PPT, Word, Excel
- 🧩 Skill System: Extend professional domain capabilities (e.g., PPT generation, Deep Research)
- 🔒 Privacy & Security: Local execution, VM isolation, high-risk command interception
**Official Website:** [https://qoder.com/qoderwork](https://qoder.com/qoderwork)
# When Developers Stop Writing Code: How 51job Redefines Programmers with Qoder
> Within 51job's technical team, a hypothesis is being validated: the future measure of programmer value will no longer be lines of code written, but AI resources mobilized.
## From "Handcrafted Code" to "Project Manager"
A widely circulated diagram within 51job's technical team illustrates three stages of developer role evolution.
Stage one is the "Executor," jokingly called "handcrafted code"—developers spend their days writing code, finding bugs, and fixing bugs. Solid work, but grueling.
Stage two is the "Collaborator," where AI begins participating in coding. Developers learn to write prompts and refine AI output, and human-AI collaboration takes shape.
Now, the company is pushing toward stage three—developers become "project managers" for AI Agents, responsible for requirement decomposition, boundary definition, and final acceptance. They steer direction rather than handwrite every line of code.
This transformation sounds radical, but 51job's approach is pragmatic: not a one-size-fits-all mandate, but starting from concrete scenarios and letting tools handle the most tedious work first.
## First Cut: Eliminating Repetitive Labor
Any programmer with large-project experience knows that truly creative thinking time is limited. Most hours go to repetitive manual work—code entry, logic structuring, writing unit tests, copy-pasting template code.
51job introduced Qoder on the IDE side to let AI handle this work. Developers describe requirements through conversation; Qoder generates code directly, and developers review and adjust.
But the real surprise for the team wasn't daily coding—it was the perennial headache plaguing all technical teams: legacy project maintenance.
## Savior of "Legacy Code Mountains"
Nearly every established internet company has "legacy code mountains"—missing historical documentation, core developers long gone, new hires staring blankly. This code is too risky to touch, too painful to maintain, yet carries critical business.

*Cao Huanglin, C-end Technical Lead at 51job, explains how RepoWiki rescues legacy projects*
51job's solution uses Qoder's RepoWiki feature: AI scans the entire codebase, reverse-generating technical documentation, sequence diagrams, and data dictionaries—making opaque legacy code transparent.
"Legacy projects often lack documentation and have lost core team members, making maintenance extremely difficult with high comprehension costs," says Cao Huanglin, C-end Technical Lead at 51job. "RepoWiki solves these problems, reducing maintenance difficulty so new hires can get up to speed quickly."
## More Than One Tool: A Differentiated Tool Matrix
51job didn't bet on a single tool. They built a differentiated tool matrix.
On the IDE side, Lingma and Qoder provide immersive AI coding capabilities, covering daily development scenarios—permission management, usage analytics, Quest mode, RepoWiki, department-level RAG knowledge bases, and other enterprise features.
More noteworthy is the introduction of QoderWork—it breaks traditional coding boundaries, enabling non-technical staff to complete business processing through natural language. For example, a department assistant can simply say "Help me verify the headers and tax numbers for all invoice PDFs this month, and generate an Excel sorted by date," and QoderWork handles it automatically.
## Management's Task: Establishing "Enterprise Dialect"
Tools are selected, but if everyone uses them differently with uncontrollable output, AI becomes an expensive toy. 51job did something critical at the management level—establishing a standardized Rules+Spec system.
Simply put: setting rules for AI. Rules unify input formats, reduce ambiguity, lower token consumption, and ensure AI output remains consistent and reproducible. More importantly, these rules transform individual experience into organizational standards, aligning AI behavior with engineering standards and business goals.
The company also makes heavy use of Quest mode in Qoder—a highly interactive, task-oriented development approach particularly suited for complex logic exploration. Developers engage deeply with AI, gradually decomposing and solving complex problems.
## Leap from Individual to Platform
Even more impressive is 51job's layout in skill management. They've built a Skills/MCP/Workflow platform, establishing a "skill leaderboard" mechanism that encourages employees to contribute automation scripts and AI skills.
This isn't a top-down mandate, but a bottom-up emergent pattern. Timesheet reporting, weekly report generation, data processing—these daily chores have been spontaneously turned into reusable AI skills by employees.
Workflow's value lies in upgrading fragmented AI single skills into organizational production systems. Through visual process orchestration, prompts, tool calls, knowledge bases, and business logic are crystallized into reusable capabilities, reducing dependency on individuals and improving overall collaboration efficiency.
## Knowledge Flywheel: Taking Experience Out of Veterans' Heads
51job's thinking on knowledge crystallization is particularly deep. They've built a "produce → crystallize → collect → distribute" knowledge closed loop.
Previously, business logic existed only in veterans' minds; new hires needed months to get up to speed. Now through knowledge crystallization, this experience is fed back in real-time to every developer's AI assistant. AI assistants can call upon crystallized knowledge to help developers access needed information faster during development, reducing repetitive work.
This creates a positive flywheel: more usage → more crystallization → AI understands business better → team efficiency increases. 51job calls this "Knowledge is Oil"—computing resources will become increasingly cheap, but enterprise crystallized knowledgebases deeply coupled with AI are the true moat.
## Elevating Measurement Standards
When developer roles fundamentally change, evaluation systems must change too.
As a tech company actively embracing transformation, 51job is driving a metrics revolution. Past developer measurement relied on lines of code, CR correction count, adoption rate—these essentially measure manual labor. Future core metrics will shift to TPM/RPM (Token consumption density), reflecting developer activity and efficiency in mobilizing AI resources.
Evaluation dimensions have also shifted from "how much code was written" to three aspects: deep business understanding, problem discovery ability, and system architecture imagination. These are the truly scarce capabilities in the AI era.
## Final Words
51job's practice paints a complete picture of AI programming adoption in large internet enterprises—not simply buying a tool, but comprehensive transformation from tool selection, standard building, skill platforms, knowledge crystallization to evaluation systems.
Qoder plays a central role: immersive IDE coding, RepoWiki's legacy project rescue, Quest mode's deep exploration, QoderWork's coding boundary breakthrough—covering full-chain scenarios from daily development to organizational empowerment.
More noteworthy is a judgment from the 51job team: the future is the "AgenticEverything" era, where everyone will have dedicated Agents that understand business, engineering, and processes. GUI operations will be replaced by LUI (Language User Interface).
In this direction, they've already taken the first step. As a leading domestic human resources service provider, 51job will actively transform its tech innovation achievements into products and services, enabling enterprise clients and individual users to enjoy AI dividends firsthand, guiding the human resources service industry toward a more efficient digital-intelligent future.
*This article is based on Cao Huanglin's offline sharing "Vibe Coding Adoption Practice in Large Internet Enterprises" as C-end Technical Lead at 51job technical team*
# Quick Start
> Choose a Qoder product, open its authoritative setup guide, and confirm your first useful outcome.
This page is the starting point for the Qoder product family. It does not repeat product-specific installation or operation steps. Choose a route below, then follow the linked guide in that product's documentation.
## Choose your route
| If you want to... | Start with | Follow this guide | Confirm this first outcome |
| ------------------------------------------------------------------ | ------------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| Develop in a dedicated AI coding workspace | Qoder IDE | [IDE Quick Start](/quick-start) | Open a repository and complete a context-aware suggestion or reviewable change |
| Keep coding in a JetBrains IDE | JetBrains Plugin | [Plugin Quick Start](/plugins/quick-start) | Sign in and complete a code suggestion, Inline Chat, or Agent task |
| Work with a repository from the terminal | Qoder CLI | [CLI Quick Start](/cli/quickstart) | Inspect the repository, make a small verified change, and review it |
| Run managed agents through APIs | Cloud Agents | [Cloud Agents Quickstart](/cloud-agents/quickstart) | Create an Environment, Agent, and Session, then receive streamed events |
| Monitor a supported IDE or CLI task from your phone | Mobile & Web | [Download and availability](/mobile/app/download) and [Remote Control](/mobile/app/remote-control) | See the same task and handle a supported approval remotely |
| Delegate document, spreadsheet, research, browser, or desktop work | QoderWork | [QoderWork Quick Start](/qoderwork/quick-start) | Complete a task and receive a usable local artifact |
| Create a digital employee for an ongoing responsibility | QoderWake | [Install QoderWake](/qoderwake/installation) | Create a Waker and complete a scoped conversation task |
| Purchase and manage Qoder for an organization | Teams or Enterprise | [Get Started with Enterprise Plans](/account/teams/get-started) | Create the organization, purchase seats, and add the first members |
For software development, start with Qoder IDE unless your existing workflow requires JetBrains or the terminal. Mobile & Web is a companion for supported IDE and CLI tasks, not a separate development runtime.
## Before the first task
1. Sign in with the account required by the selected product. Qoder and Qoder CN are separate product systems; their accounts, tasks, and data are not interoperable.
2. Use a repository, directory, or document that you can safely inspect and modify. For an autonomous product, begin with a small read-only or easily reversible task.
3. Review the applicable [Credits](/Credits), [pricing](/account/pricing), [Enterprise plans](/account/enterprise/pricing), or [Cloud Agents billing](/cloud-agents/billing) documentation before estimating cost.
4. Complete the linked product guide and verify the outcome in the last column rather than stopping after installation.
After the first successful task, continue in that product's own documentation tab for user guides, configuration, API references, and troubleshooting.
# IDE Release Notes
> Release history for IDE.
This page lists the release history for IDE, with the newest version first.
### Improvements
- The Prompt Optimization button now shows a tooltip by default, regardless of input length, making the feature easier to discover.
- Knowledge Cards now prefetch content by default for smoother loading and less waiting.
### Qoder Desktop Renamed to Qoder IDE
### Notice
Starting with version 1.24.0, the app’s display name is now Qoder IDE. This change does not affect existing features, user data, billing, or agreements.
#### \[Upcoming Change] Installation directory and executable names will also be updated in version 1.25.0 (effective August 18, 2026)
In next week’s 1.25.0 release, the installation directory and executable names will be updated as follows:
- **macOS**: Path updated to `Qoder IDE.app/Contents/MacOS/Qoder`
- **Windows**: Installation directory updated to `Qoder IDE`, executable updated to `Qoder IDE.exe`
- **Linux**: Package name updated to `qoder-ide`, executable path updated to `/usr/share/qoder-ide/qoder-ide`
If your organization relies on security allowlists, automated deployment, or software distribution controls, please update the relevant path configurations before August 18 to avoid any impact from next week’s release.
### Features
- **Code review now defaults to conversation scope**: When triggered via built-in commands, reviews now default to changes related to the current conversation.
- **Improved Spec usability**: You can now copy Spec content, quickly open its source path, and jump directly to the downloaded path.
### Improvements
- Improved knowledge retrieval in multi-repository workspaces, making cross-repo lookup more efficient.
- Enhanced prompt augmentation capabilities, with faster access to related actions via Slash Commands.
- Hooks now support passing arguments, improving flexibility and configurability for automation workflows.
- Expanded detection of potentially dangerous commands, with broader coverage of high-risk Git subcommands and stronger pre-execution warnings.
### One-click Plugin Installation via Deeplink
### Features
- **Install plugins with one click via Deeplink**: Open a link to start the installation, making plugins easier to share and distribute.
### Improvements
- Improved the default limit on conversation titles shown in the Editor view and added a clearer notice when conversations beyond the limit are hidden.
- Enhanced task execution progress displays to make each step clearer and easier to follow.
- Added one-click navigation to the bottom of a conversation for quick access to the latest message.
- Improved messaging when a model is busy for a clearer waiting experience.
- Enhanced the model selector's edit-entry styling to make the entry easier to identify.
### Voice Collaboration Upgrade, Side Task Support Added
### Features
- **Quest Live Voice supports workspace binding**: When initiating real-time voice, you can select the associated workspace. The voice task will automatically inherit the corresponding project context and be archived in the correct location.
{/* Image/Video: Quest Live Voice supports workspace binding */}
- **Real-time voice supports voiceprint recognition**: Enable voiceprint recognition in Settings - Voice - Real-time Voice to more accurately identify the current user's voice in multi-person or noisy environments.
{/* Image/Video: Real-time voice supports voiceprint recognition */}
- **Side task support**: For details or derivative issues within the main task, you can initiate associated side tasks for concurrent processing without interrupting the main task flow, improving processing efficiency.
- **HTTP Hooks support**: At key nodes such as tool calls and sessions, automatically send events to your configured HTTP interface, and based on the returned results, allow, intercept, or inject context, facilitating centralized security policies, auditing, and external integration.
### Improvements
- Added setup guidance for context and thinking mode settings in BYOK configuration.
- Optimized the default maximum round limit for goal-driven execution.
- Improved response speed for new workflow creation, reducing wait time for task creation and opening related interfaces.
- Search Agent prompt content optimized to Markdown structure, making results clearer and more readable.
- Fixed occasional WSL disconnection issues
### Improvements
- Improved how user benefits are displayed in the Usage panel.
### Scheduled Tasks Upgrade
### Features
- **Scheduled tasks capabilities fully upgraded**: Support quick task creation through sessions or manual configuration, support more types of scheduled tasks; add unified management module to make task viewing and management more efficient and convenient.
### Improvements
- Optimized knowledge card tool call switching mechanism, enhanced tool collaboration stability during answering process.
- SubAgent supports calling Skills from main session, enhancing collaborative processing capabilities for complex tasks.
### Input Box Quick Actions and Terminal Mode Upgrade
### Features
- **More convenient input box operations**: Click the "+" at the bottom left of the input box to add context, invoke commands, or switch modes. Meanwhile, the "/" command menu has been optimized for more intuitive operations and better readability.
- **Terminal now supports Full Access mode**: Once enabled, terminal commands run directly without per-command confirmation or sandbox restrictions. This mode may lead to accidental file changes, data loss, or information leakage—enable with caution.
### Improvements
- Hook PostToolUse event supports updatedToolOutput.
- Streamlined Agent prompts and tool descriptions to improve understanding efficiency and reduce irrelevant information interference.
- Optimized memory retrieval agent effects, enhancing the relevance and usability of historical information recall.
### Improvements
- improved Voice stability.
### Qoder Voice — China's first Agentic platform to launch real-time voice interaction functionality
**Speak to work:** Speak your ideas directly, instantly convert them into tasks and continuously drive progress, eliminating the tediousness of typing word by word.
**Cross-screen working:** The floating ball stays above any application, turning what you're currently viewing into context, allowing Qoder to see your work scene.
**Progress like chatting:** Discuss ideas, organize thoughts, and clarify requirements through natural conversations, light and unobtrusive to your flow state.
### Improvements
- Optimize the queuing experience for sub-agent models
- Optimize the performance of the latest ultimate model
### Improvements
### Functionality
- **RepoWiki supports multi-project knowledge generation**: Generate content for multiple projects in the Editor area at once, meeting cross-repository knowledge organization and accumulation needs.
- **Usage panel adds entitlement arrival notifications**: Receive reminders in the usage panel when entitlements arrive, staying informed of available resource changes in real-time.
### Improvements
- **Enhanced Hook interception reason display**: Added interception reason explanations to help understand and quickly handle issues.
- **More intuitive RepoWiki pre-generation settings**: Key configuration items are displayed more clearly, reducing setup barriers and improving generation efficiency.
- **Enhanced knowledge card Summary display**: The summary area after applying knowledge cards is more comprehensive, enabling faster access to key information.
- **Goal Canvas content more complete**: The generated Canvas after completion includes verification screenshots and code changes, facilitating review and sharing.
- **Enhanced memory indexing capabilities**: Improved retrieval and hit efficiency for related content.
- **Fixed Canvas share being obscured**: The sharing function is no longer blocked by new overlay mechanisms.
### Bug fixes
- Fixed occasional terminal execution timeout issue.
### Bug fixes
- Fixed Browser Use navigation failure in the built-in browser.
### Better Harness capability launched, creating better harness engineering
### Features
- **Better Harness capability launched**: Added Better Harness capability to check harness engineering practices in projects from multiple dimensions and provide targeted improvement suggestions. Supports one-click repair initiation, with Agent automatically analyzing issues and generating repair solutions.
### Functions
- **Browser annotation supports top information bar and multi-selection**: Browser annotation adds a top information bar and supports multi-selection operations, improving batch annotation and page information perception efficiency.
- **Editor conversation flow adds current round change summary**: Adds a change summary after each round of conversation in the Editor conversation flow, helping users quickly review the current modification content.
- **Quest tool area operation view optimization**: Optimizes the overall framework and layout of the right sidebar, making information hierarchy clearer and operations more convenient.
### Improvements
- Optimized Remote SSH connection process management to improve remote development stability.
- Improved terminal interaction logic to reduce interference and interruption during common operations.
- Enhanced multi-project compatibility within projects, supporting more complex project organization structures.
### Bug fixes
- Fix an occasional execution error in L2/L3 scans.
### Introducing Qoder Security
This release focuses on security for the AI coding era.
As AI multiplies code output, the weaknesses of traditional security tools — catching issues too late, generating too much noise, and producing results that are hard to understand — become even more pronounced. In this release, Qoder embeds code security review directly into the development workflow, with progressive L1 / L2 / L3 scanning that brings security checks to every code generation, every conversation, and every push. Paired with one-click quick fixes, it ensures every line of code is secure the moment it's pushed.
### Features
- **L1 Static Check**: For code generated in the current task. Uses high-risk pattern matching to instantly catch common risks like dangerous function calls and auto-fix them.
- **L2 Lightweight Scan**: For incremental code. Deeply understands code semantics to precisely identify risks such as SQL injection, remote command execution, and sensitive data leaks.
- **L3 Deep Scan**: For incremental code, tracing complete data flows across files and functions — uncovering hidden cross-file vulnerabilities invisible from a single-file view for more comprehensive analysis.
### Bug fixes
- Fixed NEXT feature issue on Windows.
### Enterprise MCP Access Control
### Features
- **Enterprise MCP Access Control**: Enterprise administrators can centrally manage members' access to MCP Servers, ensuring enterprise data security.
### Functionality
- **Rename Chats**: You can now rename chats directly in the Editor Window, making it easier to organize and manage your chats.
- **Edit Markdown Files in Preview Mode**: In Quest Window, you can now edit Markdown files right from the preview.
### Improvements
- Built-in browser now supports multiple tabs — open several pages at once to view docs, web pages, and task content in parallel.
- Improved Markdown and HTML file preview in conversation flow.
### Improvements
- Optimized the underlying architecture and implementation to improve system stability and maintainability.
### Canvas Sharing & Annotation
### Features
- **Canvas supports sharing and annotation**: Canvas now supports sharing and annotation, making it easy to share content within the enterprise and refine it directly on the canvas.
- **Supports text-to-image capability**: Added text-to-image functionality triggered by /gen-image, with generated images supporting one-click reference and download.
- **Max Round Limit for Goal**: A new setting lets you configure the maximum round limit, so you can tailor execution depth to task complexity.
{/* Image/Video: Goal supports maximum limit configuration */}
- **Bring Chat Feed Content into Your Chat**: Add content from the chat feed directly into your current chat for quick, convenient content referencing.
{/* Image/Video: Session flow content supports Add to Chat */}
### Improvements
- Improved file tree display and interactions for easier navigation in Quest Window.
- Refined plugin execution order and priority to reduce conflicts.
- Improved the Revert experience for clearer context tracking.
- Added Fork support after chats in the Editor Window.
- Enhanced the in-editor chat experience with support for Fork right after a chat ends.
### Improvements
- Optimized MCP and Skill loading logic
### Improvements
- Optimized Ultimate model performance.
### Browser Annotation Launched; Hook Enhancements, Enterprise Private Marketplace & Workspace Multi-Folder Released
### Features
- **Browser Visual Annotation**: Elements can now be selected and annotated directly during browser sessions, enabling visual debugging and page adjustments.
- **Enhanced Hook Capabilities**: Added five new events — SessionStart, SessionEnd, SubagentStart, SubagentStop, and Notification; introduced async hook re-awakening (asyncRewake); tool events now support conditional matching via if to target specific tools.
- **Enterprise Private Plugin Marketplace**: Browse, install, and use enterprise-private plugins, enabling internal plugin sharing and distribution across your organization.
- **Workspace Support for Adding Folders**: Quest supports adding multiple folders to the same Workspace, making it convenient to flexibly organize and manage multi-directory content within one workspace.
### Improvements
- Optimized Experts task dispatch strategy to avoid duplicate dispatch of same-name Experts and reduce conflicts in executing tasks.
- Improved knowledge card generation and retrieval efficiency, enhancing the experience of organizing and finding related content.
### Fork Any Chat Turn & Experience Improvements
### Functionality
- **Fork from Any Chat**: Within a Quest task, you can now Fork from any chat turn to create a new Quest and continue exploring.
### Improvements
- Improved when the right panel appears to make interactions feel smoother.
- Improved Knowledge Card for better information capacity and content organization.
- Enhanced memory self-evolution for sharper context understanding and longer-lasting recall.
- Optimized memory lifecycle management and tracking for more consistent personalized responses.
- Refined the desktop architecture for better compatibility and a more stable runtime experience.
### Plugin Marketplace & Quest Experience Upgrade
### Features
- **Marketplace management upgrade**: Added richer plugin details, flexible install scope controls, and support for managing, creating, and importing custom plugins.
- **Worktree Upgrade**: Added support for handling uncommitted changes and cleaning up worktrees, making task branch management clearer and easier to manage.
- **Quest Task Sidebar Improvements**: New grouping, sorting, and visibility customization make multitasking and task switching faster and easier.
- **Run Spec as Goal**: Once a Spec is generated, you can instantly set it as a Goal and kick off execution right away.
### Improvements
- Improved over-limit input handling with automatic conversion to file attachments.
- Improved collapsing for long conversation threads.
- Optimized sync compression to reduce overhead and improve efficiency.
- Reduced wait time for the first message in a new conversation.
- Improved Remote SSH proxy routing for more stable remote connections.
### Improvements
- Improved the follow-up input experience after pausing a Goal session.
### File Tree Enhancements in Quest Window
### Improvements
- Enhanced right-click context menu with richer file operation options
- Added drag-and-drop support for importing external files into the file tree
- Refined file tree styling to align with editor-wide visual styles
- Improved text file handling to prevent content truncation and bias
- Improved knowledge card export structure for clearer output and better usability
- Improved Canvas recognition of project configurations for more accurate code diagnostics
### Goal-Driven and Scheduling for Long-Running Tasks
This update focuses on **improving the execution experience and reliability of long-running tasks**.
Use **Spec** to structure your execution plan, or define a **Goal** to set
clear expectations—then schedule the task to kick off automatically at the
right time. No need to stay online; tasks run as planned and deliver results
when complete.
To go further, today's **Off-Peak Discount** lets you run long-running tasks
during off-peak hours at a reduced Credits cost.
### Features
- **Goal-driven execution**: Set a desired goal in Quest, and the agent will work toward that goal until completion.
- **One-time scheduled tasks**: Schedule a Goal or Spec to run automatically
at a specified time—set it and walk away.
- **Steer tasks in progress**: Jump in anytime to redirect or refine a running task without interrupting or restarting it.
- **Improved Review-to-Commit workflow**: The Quest window now covers the
full diff → review → commit → push flow, making code review and submission
smoother.
### Functionality
- **More models in Experts mode**: Qwen3.7-Max and GLM-5.2 are now available.
- **Inline annotations as context**: Add comments directly on specific content in Spec, code, or Diff views—agents will pick them up as context and respond
to your feedback precisely.
{/* Image/Video: Spec / Markdown / Diff support annotations added to context */}
### Improvements
- Reused browser state when switching between Quest task in the same workspace, reducing repeated reopening and reloading.
- Improved worktree workflow in Quest with support for handoffs.
- HTML files can now be previewed directly in the Quest window.
- Improved the empty state of the Quest file panel with clearer file-tree guidance.
- Improved logging for tool operations including commands, MCP, and Web Search.
- Improved how remote-control configuration changes are applied.
### Knowledge Engine Performance Optimization
### Improvements
- Added fine-grained categories for knowledge card retrieval, optimizing the knowledge card search results.
### Bug fixes
- Fixed a crash issue related to the Quest Window.
### Computer Use Now Available on Windows
### Features
- **Computer Use Supports Windows**: Computer Use is now available on Windows devices, expanding desktop automation to more use cases.
### Improvements
- Enhanced knowledge card type support for broader content coverage and more flexible information organization.
- Improved knowledge card retrieval for higher relevance and more accurate results.
- Optimized memory retrieval to surface more contextually relevant information, faster.
### Bug fixes
- Fixed proxy config reset causing network diagnostic errors.
### Better Control for RepoWiki, Better Chat Experience in Quest Window
### Features
- **More control before generating RepoWiki**: RepoWiki now lets you define scope and perspective upfront, with conversational planning to support collaborative knowledge generation and editing.
- **Standalone chats in Quest Window**: Start chats directly without opening a workspace, perfect for quick questions and lightweight tasks.
- **Quick Navigation in Quest**: A new sidebar in Quest Window lets you navigate directly to any target chat within a task.
- **Custom Models**: Configure context window and thinking mode for your BYOK models in the Personal edition.
- **Bring SSH Remote Control to mobile**: Manage and collaborate on remote devices with greater flexibility.
### Improvements
- Optimized Git branch selector in Quest Window to view more branches at a glance.
- Terminal tool display refined for clearer, more intuitive interactions.
- Improved evaluation and tracking for the memory agent.
### Kimi-K2.7-Code Supports Fast Mode
### Features
- Kimi-K2.7-Code now supports Fast Mode, delivering 6× faster speed for a superior coding experience.
### Support SSH Connection Multiplexing, Session Loading and Knowledge Retrieval Capability Optimization
### Features
- Support SSH ControlMaster connection multiplexing, reducing repeated authentication in remote scenarios and improving connection efficiency
### Improvements
- Optimize session loading in Quest window agent mode, enhancing the completeness of historical session retrieval and usage stability.
- Optimize knowledge retrieval performance, improving retrieval efficiency and result effectiveness to help users find required content faster.
### Quest Window Supports Mobile Remote Control
### Features
- **Quest Window Mobile Access Support**: Users can view and process tasks anytime, anywhere, enabling flexible and convenient remote operations.
- **More Model Tiers in Quest Window**: The model selector in Agent mode now offers three tiers (Performance, Efficient, and Lite) for clearer, more intuitive model selection.
- **Enhanced Expert Team and Sub-Agent Personalization**: Built-in expert agents now support custom prompts to better align with your team's standards and personal preferences. Custom sub-agents also support model configuration, making it easier to match the right capabilities to each task.
### Improvements
- Improved onboarding for the App Window Snapshot feature, helping you set up shortcuts faster.
- Improved file drag-and-drop in Quest window, expanding the droppable area for easier uploads.
- Updated the Credits usage panel with promotional activity details, including quota, usage count, and remaining balance.
- Improved knowledge retrieval accuracy and efficiency.
- Optimized local index cleanup to reduce unnecessary index overhead and improve resource utilization.
- Optimized the reporting logic to reduce sync stuttering and improve overall smoothness.
### Team Knowledge Engine and Voice Input Upgrades
### Features
- **Team Shared Knowledge Engine is now live**
- Bring User Memory, RepoWiki, and Knowledge Cards into one shared system.
- Enter /knowledge in the chat box to update knowledge anytime.
- Knowledge is stored in the cloud, maintained by the team, and used by Agents in real time.
- **Smart Polishing for Voice Input**: Automatically refines colloquial speech after transcription, making your input clearer and more natural for higher-quality interactions with Agent.
{/* Image/Video: Voice input supports intelligent polishing */}
### Improvements
- Optimized generation and update performance of RepoWiki and knowledge cards in large repositories.
- Improved knowledge hit efficiency in code change scenarios.
- Improved the performance and experience of Agent Mode in Quest Window.
- Streamlined the knowledge usage workflow, reducing the effort required to supplement project background information.
### Support for Using Dev Container in SSH Remote
### Features
- **Support for using Dev Container in SSH Remote**: Added Dev Container support for SSH Remote environments, along with the ability to attach to any Docker container, improving flexibility and consistency of remote development setups.
### Improvements
- More keyboard shortcut options are now available for App Window Snapshot, configurable in **Settings → Integration → App Window Snapshot**.
- Added a clearer entry point to sub-agent settings in the Experts model selector in the Quest Window, helping users configure sub-agents more quickly.
- Optimized the experience for handling long history sessions, maintaining more stable and smoother interactions in ultra-long context scenarios.
### Better Quest Multitasking, plus Customizable Expert Agent Models
### Features
- **Custom Tiled Layout for Quest Window**: Split the Quest window into multiple panes to handle several Quest tasks at once, with less tab switching.
- **New "My Quests" Dashboard**: Track all your tasks in one centralized view, monitoring progress across statuses to stay on top of your workload.
- **Custom Models for Experts**: Customize the models used by Expert agents in Expert Mode, choosing from built-in or custom models to fit different scenarios.
- **Code Review capability enhanced**: Run /ultra review for deeper analysis and higher-quality suggestions, helping you spot potential issues faster and improve your implementation.
{/* Image/Video: Code Review Agent review capability enhancement */}
### Improvements
- Optimized preview display effect of cards in conversation flow, making key information clearer to view.
- Optimized knowledge engine retrieval and intervention strategies before generation, improving answer relevance and hit effectiveness.
- Optimized retrieval agent memory writing logic, reducing interference from duplicate content on conversation results.
- Optimized memory agent intent recognition, retrieval recall and reflection effects, improving long-term conversation quality.
- Optimized session storage capabilities, enhancing historical content management and session continuity experience.
### New App Window Snapshot
### Feature
- **Capture the current window with a double press**:Double-press the Command (⌘) key to quickly capture a screenshot of the frontmost app window and use it as context for the agent, helping it understand what you're viewing faster. Currently available on macOS only.
### Improvements
- Performance Optimization of Knowledge Engine Generation
### Added Support for Computer Use Capability
### Features
- **Computer Use Capability Supported on Mac**: Once authorized, Agent can invoke computer operation capabilities on macOS, operate apps in the background, and complete more complex automation tasks.
### Improvements
- Relaxed file type restrictions for input box drag-and-drop, reduced file format limitations for smoother operations.
- Optimized execution methods for multiple Hooks, supporting concurrent processing to improve overall response efficiency.
- Enhanced knowledge retrieval effectiveness, helping tasks more accurately hit relevant knowledge content during the process.
- Improved LSP tool capabilities, supporting third-party package calls to enhance code retrieval and comprehension completeness.
### Knowledge Engine Optimization
### Improvements
- Optimize the overall capabilities of the knowledge engine to improve the experience of knowledge retrieval, comprehension, and result presentation;
- Refine the details after the knowledge engine's release to enhance stability and usability in daily operations;
- Enhance the quality of responses based on knowledge content, reduce interference from irrelevant information, and improve result relevance.
### Bug Fixes
- Fix potential layout misalignment issues in Markdown preview
### Model Selector Feature Enhancement
### Features
- Model Selector: Support for adjusting Context and Thinking Effort parameters.
### Improvements
- Improved behavior recommendation generation strategy for better accuracy.
### Quest mode now supports WSL connections.
### Features
- Added support for WSL connections in Quest mode.
### Improvements
- Improved code review performance in Quest mode.
### Fixes
- Fixed an issue where Do Not Disturb mode was enabled by default in Quest mode.
- Fixed an issue with incorrect background rendering in editor WebViews.
- Fixed an intermittent issue where context buttons in the input box were not displayed.
### Introducing Qoder 1.0
Since the first release in August 2025, Qoder has shipped more than 60 production releases in just nine months. Each one has been part of an ongoing exploration of a single question: how AI can truly transform software development.
From initial code completion, to Agentic Chat, to Quest mode, and then to Experts mode—we have been validating one judgment all along: AI is evolving from "assisting you to write code" to "delivering complete software outcomes on their behalf." Qoder 1.0 is our milestone response to that shift.
**Qoder 1.0, evolving from AI IDE to autonomous development desktop.**
### Highlights
- **New Quest Window & Refreshed Editor**
- Quest upgrades from IDE mode to standalone window, becoming the command center for Agent First workflow
- Editor window completely upgraded, delivering smoother human-machine collaborative coding experience
- **Cross-Project Multi-Task Parallel Processing**
- Supports multiple Workspaces running different project agent tasks simultaneously
- Unified panel tracks global activities in real-time, automatically generates delivery checklist upon task completion
- **Team Shared Knowledge Engine**
- Unified user memory, Repo Wiki, and knowledge cards for team-wide management and reuse
- Cloud-based team knowledge, collaboratively maintained and continuously used by agents (Currently in Private Preview)
- **Multi-Agent Expert Team Collaboration**
- Five types of experts: planning, research, coding, review, and testing officially join Quest, completing end-to-end delivery in pipeline mode
- Supports custom experts—configure domain knowledge, skills and tools, creating dedicated Agent teams tailored to business scenarios
### Other Features
- **Knowledge Management**: Provides more centralized knowledge access in Quest, helping users efficiently accumulate, organize and call content assets.
- **Marketplace Entry Launch**: New Marketplace module added, convenient for users to discover, obtain and manage more extension capabilities.
- **New /Canvas Visualization Generation Capability**: Supports generating interactive Canvas views through /canvas trigger, making content organization, report presentation and analysis more intuitive.
### Improvements
- Settings configuration more centralized, consolidating common settings into configuration center, reducing scattered search costs and improving personalized adjustment efficiency.
- RepoWiki adds update strategy settings, supporting enabling or disabling auto-update in settings, making knowledge content update methods more aligned with personal preferences.
- Optimized client-server reconnection path, reducing connection interruption impact on continuous usage experience.
- Improved session and command trigger path stability, reducing operation interruptions caused by exceptions.
- Optimized Quest configuration center module organization, making core capability entry clearer.
### Experience Optimization and Stability Improvement
- Optimized the retry capability of sub-agents in specific exceptional scenarios, improving task execution continuity and success rate.
- Completed code merging and capability alignment, enhancing overall functional consistency.
### Improvements
- Optimize SearchAgent performance
- Optimize ChatSession performance
### Bug fixes
- Fixed an issue where previously edited content was repeatedly highlighted in the editor diff during consecutive Agent edits.
### Qoder Community Edition Officially Released
Qoder Free Edition has been upgraded to Community Edition. The Community Edition will continue to provide Qoder's core capabilities, including code completion, Agentic Chat, Quest mode, RepoWiki, and more, helping developers efficiently complete daily development and collaboration tasks. Meanwhile, the Community Edition has opened BYOK (Bring Your Own Key), supporting users to connect their own model services for more flexible configuration and usage.
### Features
- **Support for custom model integration (BYOK)**: The Community Edition now supports configuring and using custom models in the client, meeting more flexible model selection and integration requirements.
- **Support for mainstream domestic MaaS vendors**: Currently supports integration with multiple mainstream domestic MaaS services, including: Alibaba Cloud Baillan, Kimi, DeepSeek, Z.ai, MiniMax.
### Improvements
- Optimized Chat performance
### Ultimate Model Upgrade, Comprehensive Capability Enhancement
### Features
- **Ultimate Model Grading Fully Evolved**: Equipped with the latest top-tier models, achieving comprehensive improvements in complex task reasoning, instruction understanding, and visual performance, with [limited-time half-price event launched simultaneously](https://docs.qoder.com/zh/events/ultimatediscount).
### Improvements
- Enhanced ultra-long session experience, improving fluency and usability in extended conversation scenarios.
- Linux environment compatibility with lower version glibc, expanding the range of supported runtime environments.
- Maximum MCP service connection limit removed, supporting more flexible access and management.
### Improvements
- Minor Agent improvements.
### Improvements
- Improved resilience under unstable network conditions.
### Chat Revert Experience Optimization and Retrieval Efficiency Improvement
### Features
- **Clearer chat revert operation**: Optimized interactive feedback after Revert trigger to help users more intuitively understand the rollback scope and current status.
### Improvements
- Optimized model traffic distribution strategy for search-related Agents to improve stability and response effectiveness for retrieval tasks.
### Behavior Recommendation Card Launch and Multiple Stability Optimizations
### Features
- **New Behavior Recommendation Card**: Intelligently provides next-step behavior recommendations based on current usage scenarios, improving operational efficiency and user experience.
### Improvements
- Added Agent execution loop detection to reduce interruptions and resource consumption caused by abnormal repeated executions
- Search Agent adds Wiki tool, supporting access to more knowledge retrieval sources during task processes
- Optimized processing strategies for ultra-long thinking scenarios, supporting automatic retry and guidance for continued execution in extreme cases to improve task continuity
- Reduced package size, enhancing download, installation, and update decompression speeds;
### Bug fixes
### Fixes
- Fixed an issue where update notifications appeared repeatedly on Windows.
### Bug fixes
### Fixes
- Fixed intermittent service connection failures
### DevContainer Support and Extension Host Isolation Optimization
### Features
- **Added DevContainer capability support**: Supports preparing development environments through DevContainer, helping teams achieve a consistent development experience more efficiently.
{/* Image/Video: Added DevContainer capability support */}
### Improvements
- Optimized process isolation capabilities for built-in AI coding related extensions, enhancing runtime stability and overall experience.
### Bug fixes
### Fixes
- Fixed occasional lag issue on Windows.
### Enhanced Multitasking Experience with Separate Chat Windows
### Features
- **Chat now support separate windows**: You can now open Agent chat in a standalone window, making it easier to manage multiple chats in parallel and improving overall efficiency.
- **Quest mode now supports editing sent messages**: In Quest mode, you can now edit messages after sending them, making it easier to refine your conversation and improve flexibility.
### Improvements
- **Subagents now support MCP calls**: Subagents now support MCP calls, enabling more flexible task coordination and integrations.
### Experts Mode is Here
### Features
- **Introducing New Auto Model Tier**: 50% fewer Credits than "Ultimate" tier in Experts mode, delivering high-quality output at significantly reduced cost.
### Highlights Recap
- **Multiple Experts, Working in Parallel for One-shot Delivery**: From solution design and coding to quality assurance, Experts Mode covers the entire workflow — delivering engineering-grade results in a single shot.
- **A Self-evolving AI Team That Gets You**: Continuously learns your coding style, builds up shared team experience, and evolves into an AI team tailored just for you.
### Improvements
- Enhanced Experts Canvas view with clearer collaboration visibility and smoother interactions.
- Optimized terminal execution in Experts mode with sandboxed isolation and silent operation for safer, distraction-free workflows.
### Quest mode supports Supabase and with enhanced navigation; Experts mode launches view of the full expert team; built-in browser fully upgraded
### Features
- **Expert Team Canvas in Experts Mode**: A real-time dashboard that visualizes each expert's task progress and execution workflow, giving users complete visibility into complex multi-agent operations.
- **Supabase Integration in Quest Mode**: Authorize and connect to multiple Supabase projects, with enhanced database capabilities and in-IDE preview of database table schemas.
- **Skill UI is now live:** Agents can render interactive HTML components during execution — forms, charts, config panels, and more. First use requires creating the interface.
- **Built-in Browser Upgrade**: The built-in browser has been fully upgraded, now supporting Browser Use, bookmarks, and the ability to open the debug panel.
- **Hook Support**: IDE and JetBrains plugins now support hooking into key stages of the Agent execution flow via a Hook mechanism. Five hook events are currently supported: UserPromptSubmit, PreToolUse, PostToolUse, PostToolUseFailure, and Stop.
### Improvements
- **Credits Usage**: Improved quota information display and added explanations for Shared Add-on Credits, making usage and limits clearer.
- **Quest Mode Deliverable Panel Navigation Upgrade**: Optimized interaction experience of navigation bar and file tree hierarchy.
- Improved Quest mode experience when no project is open, making it easier to find historical tasks.
- Improved the experience of question cards within the Quest mode conversation flow.
### Improvements
- Improved Quest performance for large code changes.
- Enhanced conversation context handling across sessions.
- Optimized Next prediction trigger timing in editor.
- Refined Agent file operation decision logic.
### Bug fixes
- Fixed intermittent file location errors in Quest.
- Fixed task hanging in Expert Mode.
- Fixed terminal failing to start as interactive session in Expert Mode.
### Experts Mode (Beta) is Now Available
### Features
- **Introducing Experts Mode (Beta)**: A multi-agent collaboration feature that assembles an AI expert team on demand. Describe your requirements, and the team handles everything—from solution design and implementation to testing and validation.
- **A Team of Specialists, Collaborating in Parallel**: Team Lead coordinates and orchestrates. It tracks progress throughout, consolidates results, and ensures delivery quality. Compared to single-agent sequential work, it's faster, more stable, and reduces rework.
- **Self-Evolving AI Team That Learns and Grows with You**: Expert skills continuously learn your tech stack and coding style, while team skills accumulate optimal task decomposition and collaboration patterns.
- **From "Generating Code" to "Delivering Results"**: Covers the complete workflow of requirement analysis, solution design, code implementation, test cases, and quality checks—delivering high-quality engineering artifacts ready for the next phase.
- **Fine-Grained Edits via "Add to Chat" in Quest Mode**: In Quest mode, the artifacts in the Deliverables panel now support fine-grained edits via "Add to chat" — select any content to add it to the conversation. Works for both code files and Spec files.
- **Search Agent Support in Agent Mode**: The Agent mode supports the search agent, further enhancing retrieval performance (currently effective for the Ultimate mode).
### Improvements
- In Quest mode, the task list sorting is optimized — tasks are now sorted by most recent conversation in descending order.
### Support Custom Models
- Now supports BYOK (Bring Your Own Key) configuration for easy integration with Coding Plans from providers including Alibaba Cloud Model Studio.
### Bug fixes
- Fixed Repo Wiki language inconsistency
- Fixed terminal not waiting for long commands to finish
### Agent mode supports cross-project search, VS Code base upgraded, Windows Terminal Sandbox supported
### Features
- **Agent mode supports cross-project search and file editing across the same workspace**.
- **Upgraded to VSCode base version 1.106.3**.
- **Agent mode supports Windows Terminal Sandbox**: Commands executed by the Agent can now run within a secure sandbox, effectively isolating potentially risky operations (currently in phased rollout).
- **New model supports in Quest mode**: **Qwen-Coder-Qoder**, **Qwen3.5 Plus**
- **Qwen-Coder-Qoder**: A deeply customized model built to enhance the end-to-end programming experience in Qoder. Learn more.
- **Qwen3.5 Plus**: Alibaba's latest model, delivering a comprehensive leap in reasoning capability, efficiency, and multimodal experience.
- **Repowiki**
- Core Experience Upgrades: Generation progress visualization, optimized operation guidance to distinguish between generation and updates, added import/export instructions for two-way sync, added auto-export capability.
- More efficient traceability: Projects linked to Git now automatically display Commit IDs after generation; source reference annotations now include line numbers.
- New user activity visibility: Display remaining free generation credits.
### Improvements
- The input box now supports attaching up to 20 images and 20 files.
- The file tree in **Quest mode** now supports right-click actions: Add to chat, Copy relative path, and Reveal in folder.
- Chat interaction optimization in **Agent mode** for an empty project.
### Bug fixes
- Fix the Agent busy exception issues occurring in the Quest mode
### Code Review Agent, Skills Management, Model Selection & Vercel Deployment in Quest Mode
### Features
- **/Code Review Support**: A built-in Code Review Agent is now available. Use /Code Review to start a focused review scoped to your needs.
- **Visual Management for Skills & Custom Agents**: A unified visual interface for managing Skills, Custom Agents, and Commands. Auto-create, import, and configure with ease.
- New model supports in **Quest mode: GLM-5, Kimi-K2.5 and Minimax-M2.5**
- GLM-5: Zhipu AI's latest flagship model, excels at complex systems engineering and long-horizon tasks;
- Kimi-K2.5: Kimi's latest model, excelling in multimodal understanding and complex task handling;
- Minimax-M2.5: MiniMax's latest Agentic model, combining speed, performance, and cost-efficiency
- **Use /vercel-deploy in Quest Mode**: Deploy web projects to Vercel via automated workflow, covering CLI setup, OAuth login, build, and production deployment.
### Improvements
- Improved guidance when credits are exhausted
- Custom Agents now support Skills configuration as part of their setup
- Improve the experience of open code files in Quest - Deliverables
### Bug fixes
- Fixed Quest button disappearing when LayoutControl is hidden.
### New GLM-5 and Minimax-M2.5 Model Support, Improvements to deliverables, skills in Quest mode
### Features
- GLM-5: Zhipu AI's latest flagship model, excels at complex systems engineering and long-horizon tasks

- Minimax-M2.5: MiniMax's latest Agentic model, combining speed, performance, and cost-efficiency

- Added Files to Quest mode for project file navigation and quick context addition
- Integrate Vercel Skill in Quest mode: Deploy applications directly from conversations
- NEXT supports reading clipboard history
### Improvements
- Custom Subagent execution details now support expanding in a popup for viewing
- Enhanced Skills invocation within Quest tasks
- Improved user experience for creating new tasks and collapsing sections in Quest mode
- Refreshed example content on Quest mode
### New Kimi-K2.5 Model Support
- Kimi-K2.5: Kimi's latest model, excelling in multimodal understanding and complex task handling.

### Bug fixes
- Fixed issue where new users couldn't receive quota allocation after registration
- Fixed performance issues with the Quest panel
### Bug fixes
- Fixed an issue where context with images could cause IDE crash
- Fixed an issue where switching Quest to Editor mode might cause the editor area not to display
### Support for .agents/skills
### Features
- Support for .agents/skills: Now reads skills from .agents/skills, following the industry standard.
### Bug fixes
- Fixed occasional system error issue
- Fixed occasional file editing freeze issue
### Built for Qoder: The New Qwen-Coder-Qoder Model, Elevating the End-to-End Coding Experience
### Features
- **Introducing Qwen-Coder-Qoder Model:** A deeply customized model built to enhance the end-to-end programming experience in Qoder. [Learn more](https://qoder.com/blog/qwen-coder-qoder)
This model is based on Qwen-Coder and has undergone large-scale reinforcement learning optimized for the Qoder Agent framework, tools, and scenarios. In our real-world software engineering task benchmarks, it has surpassed Cursor Composer-1 in task completion rate, particularly achieving 50% higher accuracy in terminal commands on Windows systems.
- **New Built-in Skills**: Added built-in `create-skill` and `create-agent` skills to guide and simplify the process of creating skills and custom Agents for users.
- **Quest**:Distinguish between pending changes and all changes in Review changes
### Improvements
- **One-click Prompt Optimization**: Improved handling of @Mention scenarios within prompts
- **Credits Usage**: Added display of organization Shared Add-on Credits usage
- **Installation Package Optimization**: Reduced package size and number of small files, improving update and extraction time
- **Sign in Stability Improvements**: Enhanced sign in stability (If you encounter sign in or authorization issues after upgrading, please try signing out and signing in again)
### Bug fixes
- Fixed an occasional recurring loop issue on Quest.
### Bug fixes and improvements
- Fixed an intermittent "session is busy" error occurring in Quest spec mode.
- Resolved terminal launch failure on macOS (x64 architecture).
### Invoke Skills via Slash
### Features
- Added support for invoking and using skills via /
### Improvements
- Credits usage now displays Shared Add-on Credits consumption
### Qoder v0.3.1 Official Release
In this version, we have released the following features and optimized previously released capabilities. The version is now officially updated to 0.3.1:
### Features
- **Multi-Agent Run in Parallel**: Support for multiple chat windows running in parallel, handling different tasks simultaneously, significantly improving multi-tasking efficiency.
- **Voice Input**: Added voice input support, enabling voice command control of the agent for more convenient and natural conversations.
- **Enhanced Custom Extensions**: Support for [Custom Subagents](https://docs.qoder.com/extensions/subagent) and [Skills](https://docs.qoder.com/extensions/skills) to create your own intelligent workflows.
### Improvements
- **New Windows System Installer**: Suitable for Windows multi-user environments or scenarios requiring administrator privileges to run Qoder
- **Chat Feed Display Optimization**: Tool call details are now collapsed by default
### Recently Launched Features
In addition to this update, the following features have been recently launched:
- **NEXT Brand Launch**: NES product capabilities fully upgraded with the new NEXT brand, moving from passive completion to proactive prediction for a more powerful AI programming experience.
- **Quest Mode Upgrade**: Comprehensive upgrade to autonomous programming experience, with agents capable of self-learning and evolution.
- **Qoder Teams Release**: Team edition officially launched, providing SSO support, centralized privacy mode control, and centralized billing capabilities for team collaboration.
- **Browser Agent**: End-to-end workflow from code generation to automated testing to automated debugging, also covering automated web analysis scenarios.
- **Planning Agent**: When handling complex tasks, users can leverage human-agent collaboration to pre-define actionable execution plans.
- **Custom Commands**: Support for custom Slash Commands to quickly invoke frequently used commands and improve development efficiency.
### Quest 1.0 is Now Available
### Features
- **Quest 1.0: Elevating Autonomous Coding**
- **Agent Autonomy Enhancements: Quest autonomously delivers high-quality, end-to-end, production-ready results, with minimal human intervention.**
- Powered by top-tier models: Leverages world-leading AI models for optimal results in one shot
- Requirement alignment: Intent recognition, requirement clarification, and spec co-creation to align on tasks before execution
- Long-running capability: Significantly improved long-duration task execution, with agents monitoring completion
- Quality assurance: Built-in verification automatically validates and fixes deliverables
- Continuous self-evolution: Beyond execution—actively evolves, remembers your style, and continuously learns new techniques
- **Support for More Use Scenarios: Quest recognizes user intent and automatically routes to the right capabilities.**
- Spec-driven development: Align on requirements and constraints first, then execute and verify to ensure clear, traceable results
- From idea to product: Creates websites and prototypes from scratch, with top-tier visual models for exceptional design quality and usability
- **Reimagined Interaction: Smoother and more intuitive experience.**
- Seamless mode switching: Quest entry now in the top bar—easily switch between Editor and Quest modes
- Three-column layout: Task list + conversation area + output area, redefining Quest deliverables
- Polished throughout: Refined interactions across every workflow
- **Agentic Chat: Introducing Browser and Plan agents with new capabilities**
- **[Browser Controls](https://docs.qoder.com/user-guide/chat/browser-agent)**: Agent can directly control the browser to automatically capture page source, console logs, and network requests/traffic, enabling an end-to-end workflow from code generation to automated testing and automated debugging. It also supports use cases such as automated web analysis, significantly improving front-end engineering productivity.
- **[Planning](https://docs.qoder.com/user-guide/chat/plan-agent):** When handling complex tasks, users can leverage human-agent collaboration to pre-define actionable execution plans. This significantly boosts task execution efficiency, minimizes rework, and improves both the quality of agent-generated code and the overall predictability of the results.
- **Terminal Sandbox for Mac/Linux:** Agent commands now run in a secure sandbox environment, effectively isolating potentially risky operations.
### Improvements
- Agentic Chat: Redo functionality now supports restoring manually edited code
- NEXT: Add background color to the editor area in its focused state to enhance the discoverability of completions.
### NES Fully Upgraded to NEXT
### Features
- **NES Core Capability Upgrade:** From passive completion to proactive prediction. Now supports cross-file edit prediction, automatic dependency imports, and more—enhanced capabilities with a refined user experience.
- **Context Selection Optimization:** Enhanced context menu options to support adding images, local files, and more—including drag-and-drop image insertion. Removed the @gitCommit and @codeChanges options from the menu, as the Agent can now autonomously gather relevant context. Additionally, improved the presentation of contextual content.
### Improvements
- Added QODER\_AGENT environment variable for Agent terminal execution to skip heavy shell theme loading.
### Fixed
- Fixed lag issues in certain scenarios
### Bug fixes
- Fix the problem of network request timeout in certain situation
### Bug fixes and improvements
- Fixed potential lag issues in long conversations
- Enhanced slash command input experience
### Improvements & Refinements
- Enhanced NES file rules to exclude Notebook files
- Improved Commands naming to support underscores
- Adjusted the display style for newly sent messages
### Bug fixes and improvements
- Fixed an issue where concurrent file editing could cause the Agent to hang
- Fix the problem of decline in the completion effect of NES feature
### New Custom Commands & NES Auto-Import
### Features
- Custom commands: Create reusable commands from your common prompts and workflows, and instantly invoke them in the Agent with / to streamline daily development tasks. [View Doc](https://docs.qoder.com/user-guide/commands)
- NES Auto-Import: Intelligent import completion powered by LSP
### Improvements
- Added support for adding MCP Server via DeepLink. [View Doc](https://docs.qoder.com/user-guide/deeplink)
- Remote SSH Extension now supports connecting to remote servers through bastion hosts
- Merged Qoder Proxy Settings with the Editor http.proxy settings
### Fixed
- Fixed occasional element selection failures in the preview tool
### Introducing the New "Ultimate" Model, Editable Sent Messages, and More Enhancements
### Feature
- Introducing the "Ultimate" Model Tier: Built for advanced tasks with expert-level reasoning and chain-of-thought capabilities—delivering output quality at its new peak

- Editable Sent Messages: You can now directly edit previously sent messages in the conversation stream, making it easy to refine and resubmit your request
- AGENTS.md Compatibility: Automatically loads AGENTS.md content into context when present in your project
- Repo Wiki for Non-Git Repositories: Generate Repo Wiki for local projects that are not managed by Git
- New Deep Link support: Support launching the IDE directly via the "Fix in Qoder" button in [Qoder review ](https://github.com/QoderAI/qoder-action) comments on GitHub PRs to start a repair session.
### Improvements
- Remote SSH Extension Now Supports Jump Host Scenarios: Connect to remote servers through bastion hosts
- Electron Upgraded to 37.7.0: Upgraded from 34.5.1 to address potential performance lag on macOS 26
### Support for One-Click Network Diagnostics and Windows SSH
- One-Click Network Diagnostics: Added one-click network diagnostics to quickly troubleshoot connectivity issues
- NES Settings Upgrade: Support disabling by file extension, comment section toggle. Added quick settings entry in bottom-right corner
- Remote SSH for Windows: Added Remote SSH support for connecting to remote Windows devices
- Other Improvements:
- Improved undo experience for code accept/reject operations in Diff View with Ctrl/Cmd+Z support
- Improved codebase search performance for frontend languages
- Other minor bug fixes and stability improvements
### Enhanced Task Notifications and Terminal Safety
- System notification upon task completion: When tasks such as Agent, Quest, or Repo Wiki are completed, a system notification will be triggered to alert the user if Qoder is not in the foreground.
- More accurate interception of dangerous commands in the terminal.
- Improved formatting when copying conversation content.
- Other Fixes: minor bug fixes and stability improvements.
### Enhanced Codebase Search and Built-in Mermaid Preview
- **Search Codebase**: Includes content from the Repo Wiki in search results.
- **Quest Mode**: Supports applying code changes multiple times within the same task.
- **Markdown Preview**: Built-in Mermaid diagram rendering for Markdown files, including Quest specs and Rules.
- **Issue Reporting**: Enhanced Issue Report with additional contextual information for better diagnostics.
- **Other Fixes**: minor bug fixes and stability improvements
### Major NES Overhaul and Quest Worktree Support
- **NES Comprehensive Upgrade:** Fully reimagined NES delivers superior recommendation quality, enhanced performance, and intuitive interactions for a smoother coding workflow.
- **Quest Local Mode with Worktree Support:** Added Git worktree support to run multiple coding tasks concurrently in isolated worktrees without cross-task interference.
- **Other Improvements:**
- Improved Quest Mode output quality.
- Implemented asynchronous compaction for conversation context to reduce latency.
- Enhanced Repo Wiki Mermaid viewer to support full-screen viewing, zoom controls, and one-click copy for diagrams.
- Added support for "Add to Chat" via right-click in the file tree.
- Other minor bug fixes and stability improvements.
### Introducing the Model Tier Selector and Enhancements to Quest Mode
- **Added Model Tier Selector:** Allows you to switch the AI model across four optimized tiers:
- **Auto:** Intelligently selects the optimal model to balance performance and cost.
- **Performance:** Prioritizes peak output quality by choosing the best available model.
- **Efficient:** Maximizes Credit savings with cost-effective models while maintaining high-quality results.
- **Lite:** Provides free access to the basic model.
- **Quest Mode Enhancements:** Added support for **MCP** (Model Context Protocol) and **Rules**, enabling more extensible and customizable workflows.
- **Enhanced Context Input:** Now supports a wider range of file types for upload, including PDF, Excel, DOCX, and XMind.
- **UI Improvements:** Added support for auto-pinning chats for easier tracking within the chat feed.
- **Other Improvements:** Bug fixes and performance optimizations.
### Enhanced memory management and Python development experience
- Enabled editing of auto-generated memories and enhanced their visibility in the chat feed for greater accuracy and clarity.
- Introduced a feedback mechanism for auto-generated Repo Wiki content to continuously improve its quality.
- Bundled built-in Python extensions (language server, debugging, and environment management) for a seamless out-of-the-box development experience.
- Other improvements and minor bug fixes.
### Improved user experience for prompt input and rule creation
- One-click enhancement for prompts.
- Improved input guidance when creating rules.
- Fixed several issues with rules functionality when using WSL.
- Other minor bug fixes implemented.
### Break free from local constraints with the new Quest Remote
- Quest Mode now features a new Remote Mode with GitHub repository support. You can now design a task, delegate the entire execution to a remote sandbox, and let it run asynchronously in the cloud—completely independent of your local environment.
- You can now instantly repair broken Mermaid diagrams in the Repo Wiki. Just click "Retry" on a failed diagram, and our AI will automatically correct the syntax.
- Bug fixes and stability improvements.
### At-a-glance overview of Credits directly within the IDE
- Introduced a new Credits overview, providing a clear, at-a-glance view of your subscription quota and usage directly within the IDE.
- Mermaid diagrams in conversation flows now support one-click full-screen mode, making it easier to visualize and understand complex workflows.
- The Terminal tool now maintains a persistent session within a single conversation, preserving the context and environment from previous commands for a seamless workflow.
- Resolved an issue that prevented AI-generated Git commit messages from working correctly in Multi-root Workspaces.
- Addressed an intermittent bug that could cause messages in a conversation to fail to send, improving chat reliability.
- Bug fixes and stability improvements.
### Shareable Repo Wiki and Smarter Context Control
- Qoder now generates a repository wiki in your specified language, and you can share it with others for seamless collaboration. [Learn more](https://docs.qoder.com/user-guide/repo-wiki).
- You can now monitor context usage directly in AI Chat panel, and optionally compress the conversation or start a new chat — reducing token consumption and helping you save Credits.
- You can control whether the agent is allowed to edit files outside the current project via a setting in preferences.
- Issue reporting now supports pasting images directly into the input field, enabling faster and more detailed feedback.
- Fixed an issue that prevented SSH login from macOS to remote Ubuntu 20 ARM64 machines.
### Performance boosts and smarter agent
- Enrich the agent's understanding in Quest Mode by providing context from a git commit, code changes, or even an image.
- AI now automatically creates a relevant title for each conversation in AI Chat, making them easier to find later.
- You can now configure a custom timeout for MCP tool calls in settings for more granular control over agent behavior.
- Optimized performance for very long conversations, ensuring a smooth and responsive experience.
- Enhanced Terminal interaction in AI Chat and Quest mode for faster and more reliable command execution.
- The agent now handles empty rules and conflicts with memory more gracefully, improving stability and providing clearer feedback.
- Other bug fixes and improvements.
### Support "Add to Chat" from Terminal
- Added "Add to Chat" support from the terminal.
- Improved handling of unsupported image formats in multimodal chat.
- Improved image drag-and-drop interactions.
- Fixed several edge cases with tool call errors on file edits.
- Fixed an issue with code indexing in Windows Subsystem for Linux (WSL).
- Other bug fixes and improvements.
### Support for WSL
- Added support for Windows Subsystem for Linux (WSL).
- Bug fixes.
### Hello, World!
Hey, I'm Qoder! It's great to meet you. As an Agentic Coding Platform, I'm here to help you solve real software tasks.
Let me show you how we can build amazing things together:
- **Code Suggestion:** Predict your next edit with codebase-awareness, inline suggestions. Just Tab and stay in a state of continuous, rapid coding.
- **Ask Mode:** Solve coding problems right in your IDE. No more context-switching, just solutions that keep you in the flow.
- **Agent Mode:** Coding through conversation. You maintain full control through human-in-the-loop checkpoints, turning your ideas into reality.
- **Quest Mode:** We'll start by co-designing a technical specification. Then you can delegate the task to me. I'll handle it autonomously and leave you to simply review the final result.
- **Repo Wiki:** Understand the codebase in minutes. I'll generate documentation of architecture, design patterns, and module logic once you open a project, so you can understand the project immediately.
Under the hood, I'm equipped with powerful built-in tools, enhanced context engine. This allows me to assist you with incredible efficiency and precision, making me a partner that truly understands your work.
Let's explore the future of programming and start our amazing AI coding journey together!
# JetBrains Plugin Release Notes
> Release history for JetBrains Plugin.
This page lists the release history for JetBrains Plugin, with the newest version first.
### DBML Syntax Highlighting, Expanded Diagram Rendering & Full-Access Terminal Mode
### Features
- **DBML syntax highlighting**: `.dbml` files now support syntax highlighting for a clearer reading experience when writing database schema definitions.
- **Expanded diagram rendering**: Conversations now support rendering D2, Vega-Lite, Graphviz, and QRCode diagrams, so matching code blocks from the model are displayed directly as visuals.
- **Full-access terminal mode**: When enabled, terminal commands run immediately without going through the approval flow—useful when you need to execute many commands in a row. Since commands are no longer confirmed individually, we recommend enabling this only in trusted projects and environments.
### Session Performance and Formula Recognition Improvements
### Improvements
- **LaTeX math formula recognition**: Improved recognition accuracy for LaTeX math formulas in conversations, so rendered output better matches expectations.
- **Chat history browsing**: Improved stability and loading performance when browsing chat history, making long session lists smoother to scroll through.
- **AI commit message generation**: Improved AI commit message generation for amend commits, so the result more accurately reflects the current changes.
- **Credential error messages**: Improved credential error messages for sign-in and custom models, now with clear recovery guidance when something goes wrong.
### Bug Fixes
- Fixed a compatibility issue with the DataSpell IDE.
### Queue Status Notifications & MCP Policy Status
### Features
- **Queue status notifications**: When a request is queued, the current queue position is shown and updates automatically once processing begins.
### Improvements
- **Mermaid diagram rendering**: Improved the stability of Mermaid diagram rendering in conversations.
- **MCP service status display**: MCP services blocked by enterprise policy are now shown as disabled, making it easier to distinguish policy restrictions from actual service errors.
### Sticky Question Summary in Chat, Clearer Paused-Task Resumption
### Features
- Added a sticky question summary in chat: while scrolling through a long response, the current question stays pinned at the top, and clicking it jumps back to that question.
- Added a dedicated confirmation panel when a paused task needs to be resumed, making the next step clearer.
### Bug Fixes
- Fixed an issue where a file could occasionally become uneditable after reviewing changes.
- Fixed several known issues.
### LaTeX Math Rendering, One-Click TODO Fix, and On-Demand Loading for Long Conversations
### Features
- Added LaTeX math formula rendering in chat responses.
- Added a gutter icon on TODO comments to fix them directly with Qoder.
- Added on-demand loading for long conversations: only recent messages load first, and earlier messages load as you scroll up.
- Added a clear notice with renewal guidance when your Credits are used up during a task, instead of the task appearing stuck.
### Improvements
- Improved the login flow for a smoother, more convenient sign-in.
- Improved rendering of chat responses, including smoother thinking-content display and more reliable Markdown headings.
- Improved chat font rendering in JetBrains Gateway remote development mode.
### Bug Fixes
- Fixed an issue where a chat response could occasionally stay stuck in the generating state.
- Fixed several known issues.
### Custom Agents, Computer Use & Plan Mode
### Features
- Added custom agent management, supporting creating, configuring, and invoking custom agents within the plugin.
- Added built-in agents: Computer Use and Plan Mode, with configurable run strategies in settings.
- Added session guide messages and optimized message queue display for an improved conversational experience.
- Added nested sub-agent display in the tool panel, with sub-task status summary and sub-tool collapse support.
- Added task tree visualization in the Agent tool panel.
- Added a toggle in the bottom toolbar to control whether selected text is automatically injected into context.
- Added Qoder Cleanup feature (Tools > Qoder > Qoder Cleanup) for one-click cleanup of outdated Qoder-related files.
### Improvements
- Improved Ultimate tier model performance.
- Optimized Markdown streaming rendering performance.
- Enhanced terminal experience.
- Improved session title management — user-modified titles will no longer be overwritten by AI auto-generated titles.
- Raised minimum supported JetBrains IDE version to 2021.2 (dropped support for 2020.3).
-
### Bug Fixes
- Fixed several known issues to improve overall stability.
### Bug fixes
Fixed several known issues.
### Improved Login Experience
### Improvements
- Optimized the login experience by reducing duplicate login prompts and improving login-check status display, making authentication smoother and more transparent.
- Improved network diagnostics coverage for Qoder services, enabling more comprehensive issue detection.
### Bug Fixes
- Fixed several known issues to improve overall stability.
### Fast Mode for Kimi-K2.7-Code
### Features
- Added Fast mode for Kimi-K2.7-Code, delivering faster response speeds while maintaining code generation quality.
### Improvements
- Optimized login process for a smoother authentication experience.
- Optimized chat history loading for faster retrieval.
- Added Mac Rosetta support, resolving compatibility issues when running x64 IDEA on Apple Silicon.
### Bug Fixes
- Fixed JetBrains Gateway compatibility issues.
- Fixed several known issues to improve overall stability.
### Send Text from IDE to Qoder CLI
### Features
- Added the ability to send text from the IDE directly to a Qoder CLI terminal session, enabling a smoother workflow between the editor and the command line.
- Added a Credits usage panel in the model selector for real-time quota and activity visibility.
### Bug Fixes
- Fixed occasional UI freezes during chat timeout handling.
### Qoder CLI Integration
### Features
- Qoder CLI Integration:Launch Qoder CLI directly from the IDE terminal with auto-installation, version detection, and remote session management.
### Bug Fixes
- Fixed an issue where state and resources were not properly released when a conversation ended abnormally.
- Fixed an issue where some files could not be switched in the Diff review panel when multiple files were modified in a single response.
### Model Context Length & Thinking Effort Configuration, JetBrains Terminal Support for 2025.2+
### Features
- Added model context length and thinking effort configuration in the chat model selector
- Added Terminal support for JetBrains IDE 2025.2 and later
- Added a setting to limit how many times a task can auto-continue within a single chat session
### Improvements
- Improved terminal command execution for compound commands such as cd `` && ``, ensuring commands run in the intended directory and preventing Git commands from getting stuck on pager output
- Improved Markdown link rendering and Mermaid rendering stability in chat responses
### Bug Fixes
- Fixed several known issues
### Multi-Chat Support and Connectivity Checks
### Features
- Added support for multi-session chat tabs, so you can keep multiple conversations open at the same time. Create a new tab with Alt+T / Option+T, rename tabs, and close other tabs or tabs to the right from the tab context menu.
- Added a Network Diagnostics panel in Settings to help check Qoder service connectivity and troubleshoot network-related issues.
### Improvement
- Improved chat session reliability by syncing tab loading states and preventing duplicate tabs when opening conversation history.
- Improved the stability of commit message generation and Mermaid rendering.
### Optimized user experience for personal settings page
### Improvement
- Optimized user experience for personal settings page.
### Bug Fixes
- Fixed an issue where chat sessions would occasionally freeze after plugin auto-update, requiring an IDE restart to recover.
- Fixed IDE compatibility issues on JetBrains 2020.3.
### @task — Chat with Your Jira & GitHub Issues
### Features
- Integrate JetBrains Task Management into chat context via @task, allowing users to reference issues from Jira, GitHub, and other trackers directly in conversations.
### Improvements
- Redesigned the personal settings module with a refreshed UI layout.
### Bug Fixes
- Fixed occasional out-of-order model output in chat sessions.
- Fixed an issue where AI responses could get stuck in the "generating" state with an unresponsive stop button.
- Fixed an occasional issue when clearing the current project's chat history.
- Fixed an occasional Unauthorized error with BYOK custom models.
### Support for standard Markdown format files to enable File-Based Prompting.
### Features
- Support switching the input box to Markdown editor mode, providing a standalone .amd file editing area for a larger writing space.
- Support copying table metadata from the database view context menu.
- Support SVG image rendering in the conversation flow panel.
- Slash commands are now automatically filtered by the current session mode, showing only available commands.
### Improvements
- Display a "Checking login status" loading state on the login button during startup authentication check.
- Added more built-in project ignore patterns to improve indexing performance.
### New Hook Mechanism for Agent Execution
### Features
- To provide developers with greater control over the agent lifecycle, we’ve implemented a comprehensive Hook system. You can now inject custom logic at critical stages of the agent's execution flow by listening to the following events:UserPromptSubmit, PreToolUse, PostToolUse, PostToolUseFailure, and Stop.
- New Qwen3.5-Plus Model Support
### Improvements
- Added syntax highlighting support for 80+ programming languages in chat sessions.
### Fixed
- Fixed several known issues.
### Support Custom Models
### Features
- Now supports BYOK configuration for easy integration with Coding Plans from providers including Alibaba Cloud Model Studio.
- Support to use Color Scheme Font from Color Scheme in the chat window.
### Improvements
- Optimized login interaction experience
### Fixed
- Other performance improvements and network bug fixes.
### Enhanced Context Management, SkillsJars Integration & Shortcut Improvements
### Features
- Support for context usage display and proactive compression in input box.
- Support for [SkillsJars](https://www.skillsjars.com/): right-click the resources directory to quickly create a Skill from within a Jar package via the Qoder Files menu.
- Support for creating a new session via keyboard shortcut: Alt+N (Windows) and Option+N (Mac).
- Support for adding files to the Qoder input box by right-clicking files in the project file window.
- Support for right-click for cut, copy, and paste operations in Qoder input box.
- Issue reporting now supports uploading screenshots or local images via keyboard shortcut.
### Improvements
- Issue reporting now supports uploading screenshots or local images via keyboard shortcut.
### Fixed
- Other performance improvements and network bug fixes.
### New Qwen3.5-Plus Model Support
### Features
- **Qwen3.5-Plus**: Alibaba's latest model, delivering a comprehensive leap in reasoning capability, efficiency, and multimodal experience.
### More New Model Support
### Features
- **Kimi-K2.5**: Kimi's latest model, excelling in multimodal understanding and complex task handling.
- **GLM-5**: Zhipu AI's latest flagship model, excels at complex systems engineering and long-horizon tasks
- **MiniMax-M2.5**: MiniMax's latest Agentic model, combining speed, performance, and cost-efficiency.
- **Inline Chat**: Able to switch model selection for inline chat only
### Improvements
- Auto swtich to Auto model for new users in Pro trial duration
### Fixed
- Fixed several known issues
### Built for Qoder: The New Qwen-Coder-Qoder Model, Elevating the End-to-End Coding Experience
### Features
- **Introducing Qwen-Coder-Qoder Model**: A deeply customized model built to enhance the end-to-end programming experience in Qoder. This model is based on Qwen-Coder and has undergone large-scale reinforcement learning optimized for the Qoder Agent framework, tools, and scenarios. In our real-world software engineering task benchmarks, it has surpassed Cursor Composer-1 in task completion rate, particularly achieving 50% higher accuracy in terminal commands on Windows systems.
### Fixed
- Fixed other known issues
### Bug fixes
### Improvements
- Repositioned "Qoder Files" option in the right-click context menu
### Fixed
- Fixed occasional deadlock in code completion that caused IDE freezing
### Support for adding customized skills
### Features
- **Custom Skills support**: Add your own skills and invoke them with /skill in the input field
- **Enhanced .aiignore**: Now supports .md extension for more flexible file exclusion rules
- **Quick file creation**: Right-click in Project view to create Qoder files (commands, rules, skills, AGENT.md, .aiignore)
- **Smart prompt enhancement**: One-click expansion and optimization of brief prompts
### Improvements
- Better quota limit notifications for free tier users
### Fixed
- Fixed errors when accepting code completions with Tab
- Fixed code completion not working for certain XML files
- Various stability improvements
### Manually trigger NEXT code completion
### Features
- Support for manually triggering NEXT code completion
### Improvements
- Improved experience for "Issue Report"
### Fixed
- Fixed compatibility issue with JetBrains 2026.1 EAP
- Fixed occasional login error issues
- Fixed other known issues
### Adds Database Integration and Command Capabilities
### Features
- Comprehensive Database Support
- Support for @databases as context in Qoder's Ask/Agent mode
- Support for generating and executing SQL in Query Console
- New Custom Commands
- Create reusable commands from your common prompts and workflows, and instantly invoke them in the Agent with / to streamline daily development tasks
- Enhanced PlantUML rendering capabilities
- Allow editing files outside the project through tools
### Improvements
- Optimized basic transport protocol
### Completion and NES Upgraded to NEXT
### Features
- NES Core Capability Upgrade: From passive completion to proactive prediction. Now supports file edit prediction, automatic dependency imports, and more—enhanced capabilities with a refined user experience.
### Improvements
- Improved Context Selection, include @gitcommit and etc.
### Add @openFiles for Context
### Features
- Add @openFiles annotation for Context to include all open files (project's files, SDK files, Scratch files, etc. ).
### Improvements
- Fixed several known issues.
### Bug Fixes
Fixed several known issues.
### Automatically loads AGENTS.md
### Features
- AGENTS.md Compatibility: Automatically loads AGENTS.md content into context when present in the root folder of your project.
### Improvements
- Fixed occasional abnormal credit consumption.
- Fixed the abnormal behavior of viewing changed files under history sessions.
- Fixed several known issues.
### Introducing the New "Ultimate" Model Tier
Introducing the New "Ultimate" Model Tier: provides expert-level deep reasoning and thinking capabilities, with output quality reaching a new level.
### View JetBrains Plugin Credit Usage on the Website Dashboard
- On the Website - Personal dashboard - Usage, you can now see the credits consumed in the JetBrains plugin.
- Several bugs have been fixed.
### Bug Fixes
Fixed unavailable paste functionality in CLion and Rider.
### Qoder Plugin for JetBrains IDEs!
We are excited to announce the first official release of the **Qoder Plugin for JetBrains IDEs**!
Qoder is an agentic coding platform built for modern software development. This plugin brings the power of our AI agents directly into your editor. This initial release focuses on pillars as follows:
### AI Chat
The central hub for interacting with Qoder, featuring two distinct modes:
- Ask mode: Your go-to for expert assistance. Get contextual answers, debug code, and troubleshoot errors with an AI that understands your project.
- Agent mode: Delegate complex tasks. The AI agent can autonomously use tools, make decisions, and execute multi-step plans to complete your objectives from start to finish.
### Inline code suggestion
AI-powered features that work seamlessly within your code editor:
- Code completion: Our completion engine goes beyond single-file analysis. It understands your entire project's context, dependencies, and architectural patterns to provide suggestions that are not just correct, but consistent.
- NES: Qoder anticipates your next move, offering intelligent, multi-line edits directly at your cursor to accelerate refactoring and coding.
### Autonomous task completion
This is what makes Qoder truly powerful. The agent can understand and act on high-level goals using a suite of advanced capabilities:
- Full codebase awareness: The agent intelligently analyzes your entire project to grasp the full context of a task before it begins work.
- Multi-file edits: Based on your instructions, the agent can execute complex, multi-file edits across the entire codebase.
- Persistent memory: Qoder learns from your conversations and project history, providing increasingly personalized and effective assistance over time.
- Autonomous tool use: The agent can independently select, generate, and execute necessary terminal commands, web searches, and other integrated tools to complete its objective.
- Transparent Task Planning: For any complex goal, the agent first generates a structured, step-by-step plan, giving you full visibility and control over its work.
### Customization & extensibility
Tailor Qoder to your specific environment and standards:
- Project rules: Define project-specific rules to ensure the AI's output consistently aligns with your team's coding standards and architectural patterns.
- MCP: Securely connect Qoder to your own internal APIs, databases, and other data sources, extending its capabilities far beyond the IDE.
To begin, install the plugin and open the AI Chat panel from the side navigation bar to sign in. We can't wait to see what you build with Qoder!
# Qoder CLI Release Notes
> Release history for Qoder CLI.
This page lists the release history for Qoder CLI, with the newest version first.
### Session Mentions, Settings Redesign, and Login Fixes
- Added @-mention of other live sessions in the composer, so you can reference a peer session alongside files and agents
- Improved the /settings layout: settings are shown one per row, with descriptions displayed at the bottom, so more settings fit on screen
- Changed /goal to no longer bind to Auto mode
- Fixed a stream truncated during the model's thinking phase not being retried, which interrupted the task
- Fixed login being blocked for a long time by a credential lock held by another process, and leftover locks are now recovered automatically with a retryable prompt
### Tool Call and Session Resume Fixes
- Fixed compatibility issues with streaming tool call events on some models, improving the stability of parallel tool calls
- Fixed session resume taking too long in some worktree scenarios
### Tool-Call Compatibility and Display Improvements
- Improved compatibility with some model service APIs, fixing some tool calls being skipped when tool\_call\_id values were reused
- Improved handling of host names containing non-ASCII characters, such as Chinese host names, with more accurate error messages
- Improved the TaskStop tool call card display, making the task stop status easier to read
### Command Guardrails and Tool-Call Reliability
- Added parsing of wrapper commands such as xargs and watch in the Bash tool, so the real command is correctly identified and intercepted
- Fixed pkill -f possibly killing the CLI's own process in interactive sessions on Linux
- Fixed tool calls that take no arguments failing to execute in certain interruption scenarios under interleaved thinking, such as some MCP tools
- Fixed reasoning steps arriving out of order and losing their mapping in streaming output with interleaved thinking and parallel tool calls
- Fixed /goal set failing when the objective description contains command-line options
- Fixed scheduled upgrades still running after auto update was turned off
### Plan Confirmations, Cross-Session Messages, and Long-Task Reliability
- Restored the confirmation dialog when entering and exiting Plan mode under auto and yolo modes
- Cross-session messages now show the sender and the message body inline
- Fixed shell task output files growing without limit, which could exhaust disk space
- Improved request timeout handling to resolve long-running tasks being interrupted incorrectly
- Improved diagnostics for abnormal responses, so real upstream errors are no longer hidden
- Improved the stability of multi-agent collaboration
### Prompt Draft Stashing and Session Reliability Fixes
- Added Ctrl+S to stash the current prompt draft and restore it later
- Fixed teammate agents losing memory after being woken up
- Fixed EPERM errors when running /branch
- Fixed subagent tasks failing early when their state directory was not readable or writable
- Fixed prompt rendering glitches right after a session resume finished
### Cross-Session Messaging and Scheduled Task Budgets
- Added cross-session messaging, so sessions can discover each other and send messages
- Added task budgets for scheduled tasks: set turn and credit limits with parameters, or change them in the panel
- Changed the default theme to auto, which picks the theme from your terminal background and keeps following it as the background changes at runtime
- Improved startup speed
- Fixed marketplace plugin installation failing
- Fixed input starting with an absolute path being misread as a command
- Fixed errors when switching to a non-vision model with image context
- Fixed automatic compaction using the wrong context window size
### Cleaner Status Hints and Stability Fixes
- Improved memory saving notices to be less intrusive
- Added ESC to revert an accepted next-step suggestion
- Fixed the TUI possibly freezing when dragging in images that are slow to read or inaccessible
- Fixed some historical sessions failing to resume
- Fixed task failures caused by request interruptions during the model's thinking phase
- Fixed the AbortError crash caused by canceling a request
### Status Line Enhancements
- Improved status line performance, with the option to display credits information
- Improved the startup guidance shown for the remote control daemon
- Fixed the subagent display in the TUI task panel
- Fixed /resume possibly hanging for up to 30 seconds
### Auto Memory and Stability Improvements
- Added the auto memory switch, which can be enabled in the /settings panel or in settings.json. Once enabled, it automatically saves information worth reusing from conversations for later sessions
- Removed the length limit on custom system prompts passed with --system-prompt
- Improved the model queueing experience
- Improved login reliability
### Agent Teams and Long-Session Reliability
- Added Agent Teams for multi-agent collaboration
- Improved task reminders in long sessions
- Fixed automatic context compaction not being triggered
- Fixed the Remote URL display issue
- Improved the Thinking status and Hook display interaction
### Model Preferences and Progress Display
- Added per-model memory for reasoning effort and context window settings, which are restored automatically when you switch models
- Added remote ZIP plugin installation, and fixed the plugin status not updating after uninstall
- Added the security scan subcommand, which runs security scan tasks in Headless mode
- Improved the next-step suggestion feature, offering suggestions that better match the current conversation
- Improved session status hints, distinguishing between the Thinking and Generating reply phases
- Improved image paste responsiveness on Windows and macOS
- Fixed resuming a session whose worktree had already been deleted
- Fixed unreadable error messages when context compaction failed
### Session Browsing and Scheduled Tasks
- Improved the /resume session browser: aligned shortcuts and clearer session metadata
- Improved the /crontab task panel: added a table header and clearer schedule interval descriptions
- Improved worktree stability
- Improved plugin loading logic
- Fixed duplicated image content when dragging multiple images at once
- Fixed session-level approval of plan mode not persisting
### Display Improvements and Stability
- Improved the display pages
- Bug fixes and stability improvements
### Service Account Auth and Session-Scoped Tasks
- Fixed persistent scheduled tasks being activated by unrelated sessions, and their owning session can now be managed in /crontab
- Goal creation is no longer globally unique: each session can have its own goal, and /goal take has been removed
- Entering and exiting plan mode no longer triggers a permission popup in Yolo and Auto modes
- The .agents/skills compatibility source is now enabled by default
- Removed the "Memorying..." progress indicator from the UI
- Improved the message shown when a streaming connection is interrupted
- Fixed remote artifacts failing to download on Bun binaries
- Added support for remote-controlled artifact display and download
### Session Credits and OAuth Notice
- Added server-reported session credits usage display
- Added a manual authorization reminder before MCP servers start
- Improved keyboard shortcuts for external editor operations
- Improved Bash tool execution efficiency
- Fixed /clear and /new not resetting the persistent Bash working directory back to the startup root
- Added turn progress display in goal mode to improve the interaction experience
### Rename, Skill Scanning, and Startup Improvements
- Added support for running /rename while a task is in progress
- Skill directories are now scanned recursively, with a visible warning when a declared directory contains no skills
- Improved startup speed by prewarming the shell snapshot and avoiding repeated loading of slow shell configs
- /logout now clears the login state immediately
- Fixed the external editor (Ctrl+X) failing to open in some integrated terminals such as Cursor
- Fixed input conflicts while a GUI external editor was open — the terminal is no longer handed over
- Improved the Ctrl+O detailed view toggle logic
- Improved /compact command error messages
### Loop Scheduling Upgrade and Workflow Improvements
- Upgraded /loop: the agent can now decide wakeup intervals on its own, with support for task persistence
- Added the /crontab command dashboard for viewing and managing scheduled tasks
- Added inline ghost-text completion for skill and slash commands in the input box
- The TaskStop tool now supports stopping running workflows
- Improved the Workflow TUI panel display logic
- Fixed false stall warnings while workflow agents were streaming
- The default permission mode in /settings can now be selected via options
- Fixed known issues with slash command parsing and completion
- Fixed the terminal title being lost on Windows
- Fixed skill directories failing to load when a root-level SKILL.md was present
### Prompt Suggestion Toggle and Stability Fixes
- Added a settings toggle to enable or disable prompt suggestions
- Added the .agents/skills compatibility toggle to /settings
- Fixed slash commands being reported as unknown before the command catalog finished loading, and reduced redundant catalog rebuilds
- Showed the full Bash command in the expanded shell output view
- Improved Markdown table row boundary rendering
- Fixed UI freezes when resuming long sessions
- Fixed Monitor notifications not being delivered in time
- Fixed Grep/Glob tool cross-platform compatibility issues
### Subtask Command, Feedback Enhancements, and Configurable Directories
- Added the /subtask command for dispatching background subtasks from the current session: the subagent inherits the session context, runs asynchronously, and reports back its result.
- Added /feedback argument support to prefill feedback content
- Added settings configuration to control skill loading from the .agents directory
- Adjusted the default maximum turns of local subagents to 150
- Fixed mobile conversation display issues
- Fixed long MCP user config paths not being fully displayed
### MCP Enhancements, Task Management, and Reliability Fixes
- Improved plugin validation and update logic
- Improved Ctrl+B shortcut compatibility
- Added persistent task management
- Improved WebFetch timeout error surfacing
- Adjusted model display name in headless mode
- Improved command-hook process tree teardown
### Background Tasks, Terminal Titles, and Input Enhancements
- Improved background task control with monitoring, stopping, and clearer status feedback
- Added the useProxyFromEnvironment setting to toggle reading proxy configuration from environment variables via /settings
- Improved terminal session window title updates
- Added Ctrl+K / Ctrl+U / Ctrl+W line-editing shortcuts in dialog and settings text inputs
- Improved the /resume session picker
- Surfaced argument parsing errors on stderr and aligned unknown-option output
- Fixed the subagent thinking depth setting
- Fixed image reading failures on Linux
### Compression, MCP, and TUI Improvements
- Added compression progress display in the TUI to improve the interaction experience
- Added configuration for shell command model responses, disabled by default
- Added timeout control for MCP tools
- Improved permission behavior for referenced files
- Fixed MCP list names being collapsed
- Fixed the viewport not restoring after the suggestion list closes
### Workflow Refinements
- Improved workflow pause and resume logic
- Improved Deep Research delivery and queued task dispatch
- Improved startup header and update notification display
- Improved prompts on model refusal
### Improvements
- Improved error message display
- Enhanced code security scanning reliability
### Security Scan & Model Management
- Officially released native code security capabilities
- Support refreshing the model list on demand via Ctrl + R
### Shell & TUI Experience, and Fixes
- Optimized !bash mode execution and output behavior
- Improved the built-in Deep Research workflow
- Optimized underlying network requests to improve reliability and stability
### Command Execution, Shell Experience, Exit Cleanup, and Hook Fixes
- Optimized UI rendering during command execution
- Optimized the auto-allow detection logic for read-only shell commands
- Cleaned up unfinished background tasks when the CLI exits
- Fixed an issue where the PreToolUse hook did not take effect in headless and SDK modes
### Input Experience and Stability Improvements
- Optimized CLI terminal rendering logic
- Ensured subagents honor the disallowed tools configuration
- Optimized memory usage
### Interaction Experience and Startup Stability Improvements
- Improved TUI rendering stability
- Improved the interaction experience for subagent, feedback, remote control, and other features
- Fixed some known startup blocking issues
### BYOK Configuration and Rendering Improvements
- BYOK models support context window and reasoning depth adjustment
- Added a toggle to manage plan mode in the /settings dialog
- Improved streaming performance by caching stable Markdown blocks
- Resolved abnormal color display in the TUI between rendered frames
- Reduced the impact of the status bar marquee on the user experience
- Improved the stability of worktree
### Thinking Stability Enhancements
- Enhanced the stability of the model's thinking process
### Startup Performance and Worktree Improvements
- Optimized the startup critical path for faster launch
- Improved the worktree experience
### Workflows, Skills, and Permission Refinements
- Improved workflow orchestration
- Added support for installing remote skill packages via HTTPS
- Improved the Bash tool's redirection command detection scope
- Improved error messages
- Improved the tool-calling experience
### Custom Model and Model Selector Enhancements
- Added support for custom model names for BYOK models
- Improved product interaction and onboarding experience
### Feedback Image Attachments and Experience Improvements
- Added image attachment support in the /feedback dialog
- Optimized Plan mode exit options
- Streamlined worktree tool permission checks
- Added toggle for code usage statistics in /settings
### Status Line and Model Hint Improvements
- Improved UI notifications, including status line prompts and model list hints
### Input and Display Improvements
- Support deleting pasted images as a whole on macOS
- Reduced status bar promo impact on scroll control
- Fixed context usage display issue when resuming a compacted session
- Optimized default effort label display in the model list
### Stability and UX Improvements
- Fixed a TUI rendering performance issue caused by long single-line tool output
- Improved plugin marketplace management
- Improved TUI display and some error messages
### Marketplace & Permissions Improvements
- Added plugin marketplace support
- Upgraded QoderCLI rules types with support for model-driven auto-inclusion and manual inclusion; see [https://docs.qoder.com/zh/cli/memory#%E8%A7%84%E5%88%99%EF%BC%88rules%EF%BC%89](https://docs.qoder.com/zh/cli/memory#%E8%A7%84%E5%88%99%EF%BC%88rules%EF%BC%89)
- Fixed Plan and Ask tools not being correctly disabled in headless mode
- Fixed AskUser being silently denied in auto mode
- Fixed Vim mode ESC not switching from INSERT to NORMAL during streaming
- Fixed security slash commands not responding in idle state
### Enhanced Default Permission Mode Configuration and Optimized User Experience
- defaultPermissionMode now supports yolo and dontask
- Fixed duplicate rendering of mid-turn interjection records in TUI
- Improved Background Agent display
### Plan Mode & Model Improvements
- Added --config-dir flag to override the configuration directory
- Fixed Plan mode not supporting Shell read-only commands
- Improved model connection stability
### Stability & UI Improvements
- Improved API error messages
- Optimized tool call exception handling
- Improved UI display and experience
### Dynamic Workflow and Memory Enhancements
- Added dynamic workflow support
- Added support for .qoder/rules/\*\*.md; see the Memory module in CLI docs for details: [https://docs.qoder.com/zh/cli/memory](https://docs.qoder.com/zh/cli/memory)
- Added user-level Memory and improved Memory experience in Plan mode
- Improved Headless mode startup speed
### Network Proxy Optimization
- Optimized network proxy mechanism; currently supports HTTP\_PROXY, HTTPS\_PROXY, and SOCKS5 proxies
### Startup Performance and Model Reliability
- Added configurable first-packet and stream-idle timeouts for model SSE responses
- Improved the model context window fallback strategy
- Aligned SessionEnd hook timeout and PreToolUse fail-closed behavior with strict semantics
- Tightened hook validation: hookEventName is now required in hookSpecificOutput
- Improved SDK performance for fetching the model list
### Model List Cache Optimization
- Optimized the model list cache mechanism
### Permission and Command Stability Improvements
- Fixed command truncation in permission dialogs
- Fixed git-related environment variables being cleared during command execution
- Enhanced /resume command to respect the current permission mode
### Welcome Page Refinements and Reliability Fixes
- Refined welcome panel with promotional surfaces and model promo hints
- Fixed Read tool failures caused by redundant parameter parsing
- Rebuilt Windows Git Bash download and install flow for greater reliability
### Workflow Orchestration
- Improved background task notification experience
- Fixed voice input ending behavior
### Model Panel UX and Resume Fixes
- Improved model selection panel
- Fixed interjection records not showing on resume
### Mid-conversation Messaging and Permissions UX
- Added mid-conversation interjection — messages are sent immediately during agent responses
- Enriched authorization details shown in the /permissions command panel
- Improved /resume loading performance for very large sessions
- Fixed permission prompts being incorrectly auto-approved after mode switches
### Subagent, Permissions, and UI Improvements
- Improved Hook message display style in conversation flows
- Improved interaction experience for model parameter configuration
- Refined tool permission prompt logic for selected paths
- Preserved input box content when ending a conversation with Esc
- Removed the permission request timeout limit for ACP
### Skill Commands and Model Enhancements
- Added /run, /verify, and /run-skill-generator bundled skill commands
- Added /effort command
- Aligned subagent frontmatter configuration with the existing permission system
- Fixed broken image recognition tool in Node SEA build
### Context Warning Threshold Fix
- Fixed context warning thresholds becoming inconsistent
### Queue Progress and Bug Fixes
- Added model queue progress bar with elapsed and max wait time for queued requests
- Improved auto-compact experience
- Fixed /context and status bar ratio becoming inconsistent during long sessions
- Improved Subagent display style
- Fixed MCP tool call error message display
- Improved detection of input length range errors
### TLS Trust, TUI & Stability Improvements
- Added OS certificate store trust for custom CA certificates
- Improved subagent display with event-driven transcript rendering
- Improved TUI support for IDE integration sendString input
- Improved screen TUI compatibility
- Improved /plan implementation
- Improved TUI rendering performance for large session resume
- Fixed Bash stdin redirect behavior
- Added clearer HTTPS proxy TLS handshake error messages
### Agent Sessions, Permissions Upgrade & SOCKS5 Proxy
- Enabled agent sessions by default
- Upgraded /permissions: directory completion, workspace dialog, scope-colored trust tags, and remove confirmation
- Added SOCKS5 proxy support
- Added CJK input support and prevented cursor reset in the AskUser dialog
- Redesigned the background task details panel with a structured layout and fixed empty output
- Allowed plugin hooks to bypass the --setting-sources filter
- Enhanced asyncRewake hooks with custom messages, non-interactive downgrade, and prefix matching
- Hidden symlink target paths in /memory output
- Preserved /goal ownership across resume; reset goal and permission mode on /clear and /new
- Preserved resumed conversation history when switching model or reasoning effort
- Fixed MCP `${VAR}` environment variable expansion and OAuth discovery resource mismatch
### Stability Improvements
- Fixed npm version dependency issues
### Plugin Path Placeholders and Fixes
- Added plugin path placeholder substitution (`${*_PLUGIN_ROOT}`, `${*_PLUGIN_DATA}`) in plugin content
- Fixed permission mode switch warnings repeating
- Fixed project permission rules not taking effect immediately after granting workspace trust
- Fixed Windows control character parsing issues
- Improved startup speed
### Plan Mode Independence & Stability Improvements
- Plan mode is now independent from the permission cycle — use /plan to toggle in and out, Shift+Tab cycles only permission modes
- ExitPlanMode now offers a "start goal execution" option for seamless goal transitions
- Fixed session freeze when a hook subprocess hangs on timeout or abort
- Fixed goal and plan state not restoring correctly after process restart
- Fixed module loading issues in npm published artifacts
- Improved permission mode switch warnings and ExitPlanMode options
### Model List, Promotions & Plugin Improvements
- Added --model-list flag for headless model enumeration
- Added model service queue polling with automatic recovery when the service is temporarily unavailable
- Fixed Agent(name) deny rules not taking effect from permissions configuration
- Fixed an occasional failure when resuming sessions
### Startup Performance & YOLO Mode Improvements
- YOLO mode now allows EnterPlanMode/ExitPlanMode without popups and lets AskUserQuestion pass through
- Added support for user-configurable auto-mode classifier rules from settings
- Fixed voice reconnect issues caused by stale WebSocket close events and re-activation loops, improving stability
- Improved the Windows browser login experience
- Fixed cross-window goal pollution by isolating goals per session
- Improved TUI display stability during prompt input completion
- Reduced performance impact during auto-update
### TodoWrite & UI Improvements
- Optimized TodoWrite validation recovery mechanism and error messages
- Unified info message color scheme, fixed inline code color display
- Changed cancel prompt messages to gray for improved visual hierarchy
- Fixed various other issues
### Voice Polish and Stability Improvements
- Added voice transcription polish for improved input accuracy
- Improved BYOK provider UX: disabled providers show clear explanations and better model identifiers
- Improved Review page submission confirmation interaction
- Improved YOLO mode permission denial messages
- Fixed various other issues
### YOLO Mode Revamp and Permission Improvements
- YOLO mode now fully auto-approves all tools without popups
- Made --tools flag variadic
- Improved feed stream visual hierarchy and clarity
- Fixed Windows console popups appearing during subprocess execution (windowsHide)
- Fixed pasted content in prompt input being incorrectly parsed as @ references
- Improved skill and hook loading and display
### Loop & Hooks GA
- Made /loop command and cron scheduling tools generally available for all users
- Made /hooks command generally available for all users
- Added support for startup parameter configuration via environment variables
- Custom agent names are no longer restricted to slug format
- Removed @agents autocomplete list count cap
- Improved chat feed status indicators, message spacing, and visual presentation
- Fixed various other issues
### Performance and Stability Improvements
- Improved startup performance through deferred initialization and resource caching
- Feedback diagnostic package now includes TUI text snapshot for better context
- Multiple bug fixes and interaction improvements
### Image Search, Voice Streaming, and Plugin Enhancements
- Added built-in ImageSearch tool for searching images directly within the agent
- Added voice transcription streaming, with text flowing directly into the input buffer as you speak
- Improved plugin browser UX for pending-removal items and empty marketplaces
- Fixed various other minor issues
### Reliability and UX Polish
- Added credit exhausted warning in the toast area
- Improved network fetch and model transport reliability
- Fixed voice STT terminating recording on disconnect
- Fixed schema parsing failure for built-in tool params on Qwen-style models
- Fixed various other minor issues
### Stability Improvements
- Fixed npm package runtime errors caused by incorrect tagged template encoding
### Voice, Remote & UI Fixes
- Fixed voice transcript flickering during recording and changed transcription to insert at the cursor position
- Improved Agent task execution effectiveness
### Goal, Voice & Reliability Fixes
- Fixed voice input reliability issues (recording detection, finalize timeout, multi-utterance handling)
- Improved reliability of the model invocation service
- Fixed working directory not syncing correctly in worktree sessions
- Fixed auto-permission mode incorrectly prompting for project settings file access
### Voice & Stability Fixes
- Added ElicitationResponse hook notification type
- Fixed voice mode stability issues
- Fixed session title generation failing when lite model is unavailable — now falls back to chat model
- Fixed BYOK model catalog race condition during startup
### Qoder CLI 1.0 is Now Available
**New Features**
- **Cloud Execution:** New `qodercli --remote` flag. Cloud mode lets you submit tasks once to a cloud container — shutdown and disconnection no longer interrupt execution, with support for multi-hour long-running workflows.
- **RepoWiki:** New `qodercli wiki` subcommand. Generates RepoWiki documentation locally with code never leaving your environment.
- **Voice:** New `/voice` command. Voice input fully upgraded and free to use.
- **Goal:** New `/goal` command. Keeps long-horizon, goal-oriented tasks on track without drift.
- **Open Model Parameters:** Configurable effort tiers and 1M context window support.
**Enterprise Integration**
- **Agent SDK:** TypeScript and Python installation support — integrate full Agent capabilities in a few lines of code. Programmatic-level control including tool authorization callbacks, pre-execution interception, and parameter modification.
- **Cloud Agents:** Agents-as-a-Service. Sandbox isolation, state management, async orchestration, credential management, and long-running execution all built into the platform.
**Core Capability Upgrades**
- **Orchestration:** Tasks automatically split across multiple Agents running in parallel; Main Agent decides the split strategy; each sub-Agent runs its own event loop.
- **Extensibility:** Five orthogonal extension points — Skills / Hooks / MCP / Subagent / Command.
- **Autonomy:** Agents assess risk themselves and only ask for confirmation at critical moments; automatic routing across LLM / SLM / VLM.
- **Integration:** Three integration modes — Headless (unattended CI/CD), ACP (standard bidirectional protocol), and SDK (TS / Python).
### MCP Elicitation and Stability Fixes
- Added MCP elicitation bridge support — MCP servers can now prompt users for input during remote requests
- Fixed TUI rendering crashes on resize and text wrapping
- Fixed hook execution and other stability issues
### Auto Mode Improvements
- Added auto mode option in plan approval — choose auto mode directly when approving a plan
- Auto mode now auto-allows reading files outside workspace and blocks writing outside workspace without prompting
- Fixed auto mode not being respected during plan mode for subagent tool calls
- Fixed /permissions dialog not clearing denial state on close
### Auto Permission Mode, Insights, and Windows Stability
- Added auto permission mode — LLM classifier automatically approves safe tool calls, reducing permission prompts
- Session resume now supports worktree state persistence and cross-worktree discovery
- External commands now receive workspace path, auth context, and registry environment variables
- Fixed Windows ConPTY freeze in text input dialogs (AskUserQuestion, BYOK wizard)
- Fixed Shift+Tab not working on Windows VT mode terminals (falls back to Meta+M)
- Fixed Ctrl+V paste not working in BYOK wizard on Windows conhost
- Fixed left/right arrow keys not working in AskUserQuestion text input
- Fixed ESC not cancelling /insights during execution
- Fixed MCP tools with special characters in parameter names failing (key name sanitization and remapping)
- Fixed MCP images being dropped during output truncation
- Fixed custom model key (BYOK) not being sent in API requests
- Fixed empty user messages caused by startup memory injection ordering
- Fixed QR code rendering on legacy Windows console (compact ASCII fallback)
- Fixed --setting-sources not accepting empty string to disable all sources
- Fixed WSL 1 compatibility by bumping Bun to 1.3.14
### Side Questions, Read-Only Auto-Allow, and Platform Fixes
- Added /btw side question — ask quick questions without interrupting the main conversation
- Read-only shell commands now auto-allowed — reduces redundant permission prompts for safe tools
- Worktree isolation enabled by default
- Fixed context window progress bar not updating after /compact command
- Fixed /compact command not clearing the input prompt
- Fixed color artifacts on macOS Terminal.app during cursor-forward movement
- Fixed garbled QR code rendering on Windows due to half-block characters
- Fixed batched text input on Windows causing garbled or missing characters
- Fixed fish and other unsupported shells being used as Bash tool backend
- Fixed -w flag not behaving the same as --workspace
- Fixed TUI hook deletion accidentally removing all same-command hooks
### Worktree Isolation and Context Bar Improvements
- Added worktree isolation for agents — run sub-agents in isolated git worktrees with `-w` flag, interactive exit dialog, and automatic cleanup on exit
- Added context token usage progress bar to default statusline for live context window visibility
- Fixed context window progress bar zeroing, flashing, or displaying incorrect values during compression, sub-agent runs, and session resume
- Fixed hook permission decisions not aligning with settings.json rules
- Fixed empty model response with end\_turn incorrectly treated as an error instead of graceful completion
- Fixed session title generation timing out on slow networks by increasing timeout to 180s
### Network Reliability Improvements
- Fixed network degradation chain to try original URL before falling back to resolved IPs
### Connection Stability and UI Fixes
- Added automatic retry on 504 Gateway Timeout
- Improved permission dialog path display with unified 3-tier format
- Improved MCP list to show "Needs authentication" for unauthorized servers
- Fixed duplicate content on terminal resize in alt-screen mode
- Fixed subagent ESC cancel not persisting state correctly
- Fixed workspace boundary check false positive for dotdot-like directory prefixes
### Auto-Background, Status Command, and Stability Fixes
- Added `status` subcommand for checking CLI connection and session state
- Long-running Bash commands now auto-background with completion notification when they exceed the timeout
- Improved `--model` option help text with clearer usage guidance
- Fixed Vim mode ESC not cancelling running session or shell execution
- Fixed UI stacking on Windows terminal resize
- Fixed /add-dir trusted directories still requiring read permission approval
- Fixed MCP OAuth re-authentication failing after token revocation (stale 401)
- Fixed hook status indicator persisting in TUI after hook completion
- Fixed compressed conversation incorrectly displayed after /resume
- Fixed remote control subagents not handling session reconnection properly
- Fixed symlink reads bypassing permission boundary checks
### HTTP Proxy and Shell Mode Fixes
- Added HTTP Proxy support for users behind corporate proxies
- Added Ctrl+C and ESC to cancel running bash mode commands
- Sorted slash command suggestions alphabetically
- Improved MCP server status display for unauthorized servers
- Fixed UI freeze for repetitive output in bash mode
- Fixed paste into shell mode not working
- Fixed vim ESC not exiting INSERT mode
- Fixed /resume loading excessive history beyond compression boundary
- Fixed install script architecture detection on Apple Silicon under Rosetta
### Stability and Bug Fixes
- Fixed process crash caused by network jitter (connection-level retry + runtime workaround)
- Fixed Bash tool output file growing unboundedly
- Fixed PermissionRequest hook firing twice
- Fixed /hooks TUI navigation stuck due to duplicate keys
- Fixed input box disappearing and message loss during TUI compression
### TUI Permission Dialog Improvements
- Improved TUI permission dialog UX and rendering stability
- Fixed sub-agent running status indicator display
### BYOK, Permissions & Remote Control
- BYOK Custom URL: bring your own API key with custom endpoint support
- Remote Control enabled by default
- TUI improvements: cursor handling, auth manager, and UI refinements
- Subagent shows dots spinner while running
- Validate -m model argument at startup with exact case-sensitive match
- Per-subcommand permission checking for compound Bash commands
- Disabled auto-memory feature
- Fixed hook process hangs with exit event and tree-kill
- Fixed hook permission decisions discarded on partial failure
- Windows: suppress where.exe stderr leak when rg not in PATH
- Bug fixes and stability improvements
### Hotfix
- Fixed download speed by switching to OSS accelerate endpoint
### Plugins & Stability
- Plugin variable substitution: support PLUGIN\_ROOT/PLUGIN\_DATA in hooks and MCP configs
- Improved /context panel accuracy and display
- Hook output now includes getEffectiveContext() with systemMessage fallback
- Fixed --agent system prompt not working in TUI/headless modes
- Fixed model selector not showing all entries
- Fixed /resume crash on malformed diffs
- Fixed Plan mode requiring permission to read plan files
- Fixed concurrent tool confirmations triggering listener overflow warning
- Fixed active version being cleaned up after cross-channel update
- Added Linux x64-baseline build target for CPUs without AVX
- Bug fixes and stability improvements
### Command Stability
- Fixed /tasks command unable to exit
- Fixed various other issues and improved stability
### Hook & Platform Fixes
- Fixed Hook execution failures
- Fixed newline shortcut not working in macOS default terminal
- Fixed Hook JSON output not being applied
- Fixed login errors when using xdg-open
- Fixed built-in Skills being lost during packaging
### Major Capability Upgrades: Multi-Model, Extensible, and User Experience
This is the biggest update to Qoder CLI since launch. We've rebuilt the TUI, redesigned the permission model, opened up multi-model access, and turned the CLI from "an agent in your terminal" into an agent endpoint that can be orchestrated and integrated into your workflows. Whether you're coding in the terminal, running pipelines in CI/CD, or embedding agent capabilities into your own tools — this release has you covered.
**New Features**
- Brand-new TUI — rich keyboard input support and a fully customizable status line.
- New permission model — Plan Mode plus multi-project management (/add-dir) for flexible context switching.
- Multi-model support — integrated state-of-the-art models from across the globe, with BYOK so you're no longer locked to a single provider.
- Comprehensive built-in commands — 50+ slash commands to handle your day-to-day work with ease.
- Conversational config creation — describe what you want and the agent generates the MCP / Subagent / Skill / Hook config for you. No more hand-written JSON.
### Startup Performance and Stability Improvements
- Implemented permission request queuing and sequential display for concurrent subagents
- Fixed startup blocking caused by slow network responses
- Fixed CLI crash when `.qoder.json` config file is corrupted
- Added image data output support in SDK mode
### Remove Code Review Restrictions
- Removed usage restrictions for /review and /setup-github on free subscription
- Bug fixes and stability improvements
### Thinking Rendering Support
- Added thinking/reasoning process rendering in chat for supported models
- Updated Windows hook execution to run via Git Bash
- Optimized Windows Git Bash download and installation for faster setup
### Custom Model Support
- Support for custom models with providers like Alibaba Cloud Bailian Coding Plan
### Skills and MCP Enhancements
- Added Skills loading support from .agents directory
- Added Skills support via symbolic links
- Added automatic MCP Server type inference
- Hidden /compact command results with Ctrl+R to expand and view
### New Model Support
- Add support for Alibaba's latest model (Qwen 3.5 Plus)
### New Model Support
- Add support for new MiniMax model
- Fix WebFetch tool execution errors
### New Model Support
- Added support for new models
- Improved Todo task generation rules
- Enhanced viewing logic for MCP tool execution results
### Improved Configuration Loading
- Optimized the resource loading order for skills, commands, etc.
### Enhanced Configuration Capabilities
- Added creation of Subagent Skill
- Added `mcp auth` sub-command to authenticate with an OAuth-enabled MCP Server
- Added --mcp-config flag to load mcp servers from JSON string
### Bug Fixes
- Refactored Glob tool implementation
- Fixed issue where invalid images would prevent conversations from continuing
- Fixed intermittent request failures caused by tool execution returning no results
- Fixed account switching conflicts when running multiple processes concurrently
- Fixed unauthorized error when running /upgrade command on Teams plans
### Bug Fixes and Improvements
- Optimized token estimation logic for images in context
- Fixed rg execution errors in Linux ARM64 environments
- Fixed panic issues caused by MCP configuration errors
- Fixed MCP query subcommand display issues
### Bug Fixes and Improvements
- Added --with-claude-config to load Claude Code Skills, Commands, and Subagents
- Improved zsh shell priority on macOS
- Fixed TUI crash issues
### Bug Fixes and Improvements
- Fixed file retrieval errors on macOS with ARM chips
- Fixed Glob tool search not canceling properly
- Fixed context overflow when switching models
- Added persistent logging for Bash tool execution
- Improved AskUserQuestion accuracy
- Fixed -w parameter not recognizing relative paths
### Skills Support
- Added /skills command to view Skill configurations
- Added --agents parameter for subagents configuration
- Improved Markdown rendering in TUI
- Fixed trailing newline being removed when editing files with Edit tool
- Fixed Bash tool execution failures on some older Windows versions
- Fixed streaming output issues for commands in TUI Bash Mode
- Fixed inability to execute multi-line commands in TUI Bash Mode
- Removed minimum window size restriction in TUI
- Fixed /resume command failing to restore certain conversation sessions
### Conversation Export Support
- Added /export command to export conversation history
- Added automatic git-bash setup for Windows
- Added current working directory to status bar
- Enhanced AskUserQuestion tool interaction in TUI
- Improved context compression
- Fixed several issues
### Improvements and Bug Fixes
- Added plan expiration date to /usage command
- Improved Bash command parsing
- Fixed conversation hang after canceling tasks on certain models
- Fixed http/https prefix being stripped from tool parameters in TUI
- Fixed Init command in Zed integration
### ACP Support
- Added --acp flag for ACP support
- Added streaming support for tool parameters in TUI
- Fixed Subagent configuration file parsing errors
### Model Configuration Enhancements
- Added support for setting maximum output token length (--max-output-tokens parameter and /config option)
- Added --model parameter to specify model at startup
- Fixed OAuth authorization issues with certain MCP Servers
- Improved TUI display for /model command
### Model Tier Support
- Added /model command to switch between model tiers
- Improved Edit tool validation logic for better file modification performance
- Enhanced TUI display rendering
- Fixed inability to restore input history with @file references
### Improvements and Bug Fixes
- Added attachments flag in headless mode for image attachments
- Removed auto-generation of permission config files in new directories
- Added retries for failed reasoning requests
- Miscellaneous fixes and improvements
### TUI Performance Optimization
- Optimized message caching to enhance TUI rendering performance
- Fixed Webfetch tool panic on rejection
- Fixed TUI rendering issues in Windows WSL
### GitHub CodeReview Release
- Released GitHub CodeReview feature
- Added version and other metadata fields to message history
- Fixed issues and improved user experience
### Tool Permissions Improvements
- Added permission prompts when tool (including MCP) output is very large
- Fixed bundled ripgrep failures on Linux
- Adjusted log output location and fixed other known issues
### Improvements and Bug Fixes
- Removed incremental messages from stream-json output in headless mode
- Disabled automatic backfilling of environment variables (e.g., QODER\_CURRENT\_WORKDIR) in mcp config files
- Fixed display corruption from multi-line descriptions in subagents and commands
- Fixed inability to delete attached files on Windows
### Streaming Output and Ultra Plan Support
- Added Ultra Plan support
- Added code syntax highlighting
- Implemented streaming output and enhanced TUI rendering performance
- Enabled command execution in headless mode
- Improved error handling for image file processing in Read tool
- Fixed Cygwin path compatibility issues with Read tool
- Fixed WebFetch tool crash when processing large web pages
### Improvements and Bug Fixes
- Added version update notifications
- Changed default permission paths to relative in new repositories
- Fixed Glob tool crash when search results exceed 200 items
### Qoder Personal Access Token Support for Headless Mode
- Added Qoder Personal Access Token login support
- Optimized text pasting performance on Windows for large content blocks
### Windows Compatibility Fix
- Fixed file modification failures on Windows caused by CRLF line endings
- Enhanced error messaging for failed custom Subagent and Command operations
### Windows Terminal Support Unlocked
- Removed usage restrictions in CMD and PowerShell terminals on Windows
- Optimized newline insertion logic for improved text wrapping at any position
- Fixed a panic in /resume command when used in newly initialized project directories
- Enhanced Command and Subagent generation pipeline to increase result parsing accuracy
### OAuth MCP Integration Release
- Added OAuth support to the /mcp command for MCP Server integration
- Increased default output token limit from 8K to 16K
- Updated /bashes command to display only background tasks
### Cross-IDE Support Enhancement
- Enhanced the /login command interface
- Removed usage restrictions in JetBrains and VS Code terminals on Windows
- Fixed a bug in the WebFetch tool that caused the agent loop to exit
- Improved error messages for request-related failures
### Model Accuracy and User Experience Refinements
- Removed @ symbol references from sent content to improve model accuracy
- Fixed Bash-related tools to keep agent loop after permission denied
- Added user-friendly prompts for common exception scenarios
### Installation fixes and general improvements
- Fixed npm package installation problems on Windows and Linux platforms.
- Fixed an issue where some existing users would crash after login.
- Fixed backspace behavior at line start in special modes.
- Enhanced TUI display and refined text content for better user experience.
### Welcome to Qoder CLI
Hey, I'm Qoder CLI! It's great to meet you.
I'm here to bring the full power of AI-assisted development right into your terminal—where you do your best work. No context switching, no heavy IDEs. Just you, your command line, and an AI partner that truly understands your codebase.
Here's how we'll work together:
- Quest Mode: Delegate complex tasks to me. Describe what you want, and I'll design the solution, implement it across files, run tests, and deliver working code. You stay focused on what matters—I'll handle the rest.
- Agent Mode: Code through conversation. Ask me anything about your project, and I'll help you debug, refactor, or implement features with full human-in-the-loop control. Get instant answers with full context of your codebase.
- Custom Commands & Subagents: Turn your repetitive workflows into executable commands. Whether it's generating migrations, updating docs, or running security checks—your team's knowledge becomes automation.
- Seamless Integration: I fit into your existing workflow. Git-aware by default, shell-native by design, and ready to integrate into CI/CD pipelines. I work with the tools you already love.
Powered by an advanced context engine and intelligent tooling, I understand your entire codebase to assist you with incredible efficiency and precision—making me a partner that truly gets your work.
Ready to code at the speed of thought? Let's ship. 🚀
# Cloud Agents Release Notes
> Release history for Cloud Agents.
This page lists the release history for Cloud Agents, with the newest version first.
### Features and improvements
### ✨ New
- Agents support Browser Use — open web pages in a session, read page content, and complete web-based interactions and analysis
### 🔧 Improvements
- QCA Assistant can suggest Agent configuration improvements, recommend usage modes, and generate integration code samples for your scenario
- Session credit charges are shown per conversation turn for easier usage reconciliation
### Features and improvements
### ✨ New
- Batch API: submit large job sets via JSONL, with off-peak execution, cancellation, and result download
- Schedule runs in an isolated session and can deliver results back to the source session; nested Schedule management is blocked during a run
- Create or update Skills with natural language, and mount GitHub repositories for Agents
- Stronger Channel observability; thinking payloads available when thinking events are requested
### 🔧 Improvements
- More reliable Batch / Schedule recovery under failures and concurrency
- Clearer Identity and Skill lookup / conflict messaging
### Console Forward Mode and experience updates
### ✨ New
- Console supports switching to Forward Mode with separate navigation for each mode
- Console adds a Forward template debugger — create debug sessions, send messages, upload attachments, inspect event streams, and handle tool approvals
- Console observability overview — active Sessions, success rate, Token / Credit usage, 7-day trends, and details
- Console usage and quota views — monthly usage, remaining budget, daily consumption, and dimension-level changes
- Memory Store now supports Agent read and write, so Agents can organize and maintain their memory while working—persisting key information and reusing it in later tasks for more coherent context accumulation
- Agents now support native image recognition, understanding and reading images directly within a conversation with faster, more efficient image parsing for smoother handling of image-related tasks
### Forward Mode Launch: Deliver Agents to End Users and Business Systems
### ✨ New
- Forward Mode is now available — deliver pre-configured Agents to end users with just template\_id + identity\_id
- Forward Templates and Identity — admins preset Agent templates; Identity injects per-user configuration (tools, Skills, files, memory stores, env vars) with automatic memory and permission isolation
- Forward Schedule: cron, one-time, and manual triggers — runs on schedule and can push results to IM channels
- Forward Channel: built-in IM integrations (DingTalk, Feishu, WeCom, WeChat, Slack, and more) — messaging, QR binding, approvals, and file intake
- Forward Schedule: create, query, and delete schedules via natural language; monitoring tasks support start/stop windows
- Forward Channel: Lark integration — QR registration, long-lived sessions, messaging, and streaming card updates
- Forward Channel: per-region channel availability and user quota configuration
- Forward Identity / Channel: Runtime Channels auto-archive and stop sessions when Identity is deleted or Template is archived
### 🔧 Improvements
- Stronger validation and stability for Forward Mode enterprise integrations
- Forward Schedule: fair queuing and automatic recovery for stable operation under high concurrency
- Forward Schedule: hot-reloadable dispatch parameters — no service restart required
- Forward Schedule: natural-language schedule creation prompts for missing details when input is incomplete
- Forward Channel: stronger Runtime Channel security and user ownership checks with reduced credential exposure
- Forward Channel: improved approval and streaming card UX — fewer cross-session mix-ups
### Event-Driven + Vision: Making Agents More Proactive
**✨ New**
- Agents now include built-in ImageSearch and ImageGen tools — search or generate images directly in conversations
- Webhook support for event-driven push notifications — get real-time Agent/Session lifecycle updates at your registered URL without polling
- Choose model context window size (e.g. 200K, 1M) when creating an Agent to fit different workloads
- File uploads now accept images, documents, archives, and audio/video formats
**🔧 Improvements**
- Session input redesigned with a ChatGPT-style send/stop toggle for more intuitive control
- Skill and MCP chips in sessions are now clickable to view details
- MCP server configuration adds an "Interaction Strategy" option
- Skill Marketplace now supports multi-select and one-click batch import for faster Agent setup
- Session detail page adds Agent / Environment / Vault tabs for quick access to related resources
### Cloud Use Launch: Let Agents Operate Cloud Services Autonomously
This release centers on the **Cloud Use** thesis: Agents are no longer just conversational assistants — they are autonomous units that securely invoke cloud APIs under a machine identity. Together with the Diagnostic Assistant and Session Dynamic Patch, the full loop from assembly to debugging is dramatically faster.
### ☁️ Cloud Use — One Task, Full Cloud Loop
No human needs to stay online. The Agent operates under a machine identity, securely calling Alibaba Cloud services via the MCP protocol — from running SQL on MaxCompute to orchestrating DataWorks pipelines — completing the entire cloud workflow in one shot.
- **One-click skill assembly**: Browse the Qoder Skill Center with the Alibaba Cloud section pinned at the top, multi-select and batch import supported, from discovery to deployment in a single flow
- **Secure MCP credential hosting**: Vault-backed credential groups with collapsible organization and lazy loading, OAuth wizard with guided setup (including a dedicated Alibaba Cloud Use onboarding flow) — secrets never leave the Vault, Agents call transparently
- **Single-pane Agent setup**: Import skills → bind MCP credentials → configure permission policies → create Agent, all completed in one console without switching tools
### 🩺 Diagnostic Assistant
When a Session stalls, errors, or behaves unexpectedly, the Diagnostic Assistant handles "locate → root-cause → recommend" entirely within the console — no more digging through logs to piece together context.
- **Real-time diagnosis**: Automatically identifies errors, infers root causes, and provides actionable fix suggestions
- **One-click context pull**: Events, turns, and tool\_calls are collected automatically as diagnostic input — no manual export needed
- **Shareable conclusions**: Diagnostic results can be exported, copied, or shared — paste into tickets or sync with the team
### 🔄 Session Dynamic Patch
Running Sessions now accept live configuration changes — no need to archive and recreate.
- **Instant config delivery**: PATCH tools and mcp\_servers; changes take effect on the very next turn
- **Zero-interruption debugging**: A/B test prompts, add tools on the fly, swap models — without restarting the session
- **Context preserved**: Configuration changes do not discard existing conversation or execution history
### 🔧 Improvements
- MCP tool picker now supports collapsible groups, lazy loading, and type filtering for quick navigation in long lists
- Skill package downloads use native browser downloads, eliminating cross-origin compatibility issues
- Self-hosted mode no longer force-injects workdir; uses relative path prompting instead, better aligned with local engineering workflows
- Deployment creation and run UX improvements: resource config prefill, correct initial event block rendering
- Skill center import button permanently anchored in the bottom action bar — no more scrolling to find the confirm action in multi-select scenarios
- Environment list shows a "Self-hosted" label for self\_hosted type entries, making environment ownership visible at a glance
### Bring Your Own Infrastructure, Reach Private Tools
This release evolves the Agent from a single cloud execution environment into an open system — bring your own infrastructure, reach private-network tools, and programmatically initialize your environment.
### 🏗️ Self-Hosted Sandbox
Run agent tool execution on your own infrastructure while LLM inference stays in the cloud. Your code, filesystem, and network egress never leave your environment — ideal for data compliance and private network access.
- Create a `self_hosted` environment; workers listen to and execute tasks via the Work Queue protocol
- Supports Go SDK, CLI, and direct HTTP integration in any language
### 🔌 MCP Connector
Securely and reliably expose private-network MCP servers to Cloud Agents through a Connector — no need to open internal services to the public internet.
- Create Tunnel → Start Connector (SSE reverse connection) → Bind tunnel\_id to Session — three steps to completion
- Domain allowlist + IP-level SSRF protection for a clear security boundary
- Horizontal scaling with multiple Connector instances per Tunnel for load balancing
### 🛠️ Worker setup\_script
Workers run a custom initialization script before tool execution begins. Use it to install dependencies, pre-configure the environment, stage resources, or inject credentials. In sandbox mode, it runs once per session before the first tool call.
### 🔧 Improved
- Tool execution duration display uses wall-clock anchoring, eliminating timer jumps caused by streaming rendering
### Multi-Agent Collaboration, Environment Variables, Intelligent Memory, Scheduled Deployments
This release evolves Agents from "single-role, one-shot conversations" into a full system of multi-role collaboration, cross-session memory, and automated scheduling.
### 🤝 Multi-Agent Collaboration
Orchestrate multiple Agents within a single session — each runs in its own thread and communicates via a Mailbox mechanism. Ideal for splitting complex tasks into multi-role pipelines (e.g., research + code + test) without manual coordination.
### 🔑 Environment Variables
Pass custom key-value environment variables when creating a session. Agents access them directly via `$ENV_NAME` in the Sandbox. Perfect for injecting database URLs, API keys, and other runtime config without hardcoding them in prompts.
### 🧠 Dreaming (Intelligent Memory)
After a session ends, the platform automatically reviews the conversation, extracts key insights, and writes them to a Memory Store. The next time the same Agent starts, it loads existing memories — enabling persistent context accumulation across sessions. The more you use it, the better it knows your project.
### ⏰ Scheduled Deployments
Configure cron-based recurring triggers or trigger manually with one click. Full lifecycle management included: pause / resume / archive / auto-retry / auto-pause after consecutive failures. Ideal for daily reports, periodic health checks, and data synchronization workflows.
### GitHub Repos, Model Freedom, and Tool Control
This upgrade focuses on making Agent inputs smoother, model selection freer, tool execution more controllable, and the overall experience more stable. It covers four themes: GitHub repository mounting, new model catalog, custom Agent tool support, and a batch of bug fixes and UX improvements.
### 🔗 GitHub Repository Support
- Mount GitHub repositories directly as session resources when creating a session — no need to clone locally and upload. One less step.
- Inline GitHub Personal Access Token input on the session creation page. Private repos are ready to use on the spot — credentials apply to the current session only, no separate vault configuration required.
### 🤖 New Model Catalog
- Added support for multiple partner models in one go — Qwen, DeepSeek, GLM, Kimi, MiniMax, and more — with a unified `${price_factor}x` credit multiplier display, making it easy to pick the right model for the task and budget.
### 🛠️ Custom Agent Tool Support
- Agents can now declare `type: custom` tools with execution logic implemented on the client side, letting you extend Agent capabilities per your business needs without being limited to the built-in toolset.
- Three-tier tool permission policies: `always_allow` for auto-execution, `always_ask` for user confirmation before execution, and `always_deny` for outright rejection. Human-in-the-loop lands for the first time — sensitive actions can require manual approval.
- MCP tools can be authorized by server prefix in one shot. Configure once and all tools under that server are permitted — no more checking them off one by one.
### 🐛 Bug Fixes & UX Improvements
- Session event list now supports cursor-based pagination with infinite scroll — sessions with more than 100 events are no longer silently truncated.
- Files page sorts by creation time descending with the newest file on top; new "Purpose / Status / File ID" columns and one-click copy.
- SSE event streams support Last-Event-ID resume after reconnects — network hiccups recover automatically with no manual page refresh.
- 10-second session list polling no longer causes full-page flicker; the event panel has its own scroll container and no longer drags the whole page.
- Agent edit mode skill display is now fully consistent with the detail view; hitting the 20-skill cap shows a friendly inline error and blocks submission upfront.
- Pressing Enter during IME composition no longer sends the message prematurely; file mount paths no longer produce `/data/data` double prefixes.
- Feedback dialog supports image upload and one-click viewport screenshot, moved into the Settings menu for a smoother reporting flow.
- Sessions stuck in the cancelling state now auto-recover; concurrent resource additions run under `FOR UPDATE` locks to prevent overwrites.
- Skills zip uploads automatically normalize Windows backslash paths for consistent behavior across Mac and Windows.
### Agent artifacts downloadable
### Agent artifacts downloadable via Files API
**✨ New**
- Smoother real-time event streaming: automatic reconnection with resume-from-last-event after network interruptions — no page refresh needed.
- More flexible file mounting & downloads: custom mount paths for uploaded files with no directory restrictions; agent-produced artifacts are now downloadable via the Files API.
**🔧 Improved**
- Session detail layout refined — event list and detail panel now scroll independently.
- Enter key no longer sends messages prematurely during IME composition (Chinese, Japanese, etc.).
**🐛 Fixed**
- Fixed an issue where some agent sessions would get stuck due to misconfigured tool permissions.
- Fixed sessions staying in "Cancelling" state indefinitely without completing.
### Qoder Cloud Agents Beta Release
### Qoder Cloud Agents is now in public beta — deploy persistently running, self-evolving AI Agent cloud services via REST API.
Qoder Cloud Agents is a fully managed AI Agent platform with a built-in reasoning execution engine and tool runtime environment, providing persistent storage for task conversations and file history. Through the separation of "brain" and "hands," it enables management of arbitrary execution environments while ensuring data security. Developers can quickly build their own applications by directly invoking Cloud Agents via API.
### Core Capabilities
- Agent API: Declaratively create and manage Agents (models, tools, system instructions, MCP integrations), with version management and rollback support
- Managed Environments: Securely isolated Sandbox execution environments with configurable network policies — no infrastructure to build or maintain
- Long-Running Sessions: Continuous execution for up to 26 hours, with checkpoint resume support and event-stream-based state persistence
- Built-in Toolset: 8 out-of-the-box tools (bash, read, write, edit, glob, grep, web\_fetch, web\_search)
- MCP Extensibility: Connect to external MCP Servers for unlimited extensibility
- Real-time SSE Event Stream: Full observability — every reasoning step and tool call is pushed in real time
- Self-Evolving: When the platform upgrades models and orchestration strategies, integrated applications automatically get stronger with zero code changes
### API Endpoints
- `POST /v1/cloud/agents` — Create an Agent
- `POST /v1/cloud/environments` — Create an execution environment
- `POST /v1/cloud/sessions` — Create a Session (binding Agent + Environment)
- `POST /v1/cloud/sessions/{id}/events` — Send a message
- `GET /v1/cloud/sessions/{id}/events/stream` — Stream responses (SSE)
### Additional Features
- File upload and management support (Files API)
- Secret injection support (Vaults API)
- Skill packages support (Skills API)
- Persistent memory support (Memory Stores API)
- Quickstart Console: from zero to your first running Agent in 60 seconds
# QoderWork Release Notes
> Release history for QoderWork.
This page lists the release history for QoderWork, with the newest version first.
### Everyday Polish
This release fixes skill installation and conversation display issues, with clearer error messages.
**🐛 Fixes**
- Fixed skill installation failing in certain cases
- Fixed history messages occasionally overwriting the current conversation
- Improved error messages for clearer descriptions
- General stability improvements
### Everyday Polish
A focused round of fixes for a smoother, more reliable session experience.
**🐛 Fixes**
- Fixed occasional ghosting and overlapping messages when scrolling the conversation view
- Fixed tool confirmation dialogs reappearing in older conversations
### Everyday Polish
This release fixes several issues affecting conversations, voice input, and the skill marketplace.
**🐛 Fixes**
- Fixed messages occasionally overlapping in the conversation stream
- Fixed voice input failing to connect in proxy network environments
- Fixed category filtering and pagination in the skill marketplace
- Fixed IM message replies occasionally being lost or arriving out of order
- Fixed incomplete conversation loading when switching between tasks
- Windows: Adjusted the default voice input shortcut to avoid system conflicts
### Only Your Voice Gets Through
Voice input now supports voiceprint isolation — background voices no longer make it into your transcript. The built-in docx and pptx skills also get a systematic upgrade.
**✨ New**
- **Voiceprint isolation for voice input**
Turn on the new Voiceprint toggle in voice input settings (off by default). Each time you start recording, QoderWork picks up your speaking profile from the opening moment of the session, then keeps only your voice in the transcript — nearby chatter, distant conversations, and ambient noise are suppressed before ASR and any post-polishing. Meetings, cafes, or a chatty room won't leak in anymore.
- **docx & pptx skills refreshed**
Generate polished Word documents and slide decks from a single prompt — docx now supports template filling and direct Markdown-to-DOCX conversion, and pptx produces more consistent, cleaner output.
- **Knowledge base ZIP upload & large-file direct transfer**
Upload entire ZIP archives to your knowledge base, and large files now use a direct-upload channel for better speed and reliability.
- **Dock / taskbar unread indicator**
Both macOS and Windows now let you toggle the unread badge on the Dock or taskbar icon from Settings.
**🔧 Improvements**
- **Refined context-window dialog**
The dialog for setting each model's context window (accessed from the model picker) has been cleaned up — clearer fields and smoother switching.
- **Connector Market routing**
The Connector, Skill, and Plugin marketplaces now filter by product and version so only relevant items show up.
- **Fullscreen for in-chat MCP apps**
MCP apps in conversations now support fullscreen mode, with side-canvas state preserved.
- **Personal top-up entry**
Personal credit top-up is now reachable from both Settings and Usage overview.
**🐛 Fixes**
- Resolved quality-of-life issues across knowledge base, Connector Market, and MCP apps
- Improved Windows update flow and overall stability
### 1M Context Window
This release introduces per-model context window settings — configure up to 1M tokens for each model. Voice input also gets a major upgrade with hands-free auto-send and faster polishing.
**✨ New**
- **Context window settings**
A new "Model Settings" entry at the bottom of the model picker lets you set each model's context window size (up to 1M tokens) — applies globally once configured.
- **Hotkey auto-send**
Press the voice hotkey to start, press again to stop — and it sends automatically. No more extra tap on the send button.
**🔧 Improvements**
- **Faster voice polishing** — Polished text appears almost instantly after recording stops, with no visible delay.
- **Clearer archive prompts** — The archive confirmation dialog now shows the path to find archived items later.
- **More syntax highlighting** — Markdown previews now highlight additional popular programming languages.
**🐛 Fixes**
- Fixed Windows installer type detection causing wrong update packages, broken shortcuts, and browser connector path errors
- Fixed network connections dropping when system proxy is unavailable
- Fixed miscellaneous UI issues including HTML preview white screen, voice preview overflow, and paste formatting artifacts
### Slack IM Channel
QoderWork now connects to Slack as an IM channel — native streaming replies, on par with the other IM channels. This release also brings the MCP Apps protocol along with enterprise-grade MS365 access.
**✨ New**
- **Slack IM channel**
A new Slack IM channel connector with native streaming replies, on par with DingTalk, Feishu, and other supported IM platforms.
- **Suite sharing**
User-created expert suites can now be shared via a link — colleagues open the link and use the suite out of the box. Built-in marketplace suites do not support sharing yet; this will be enabled in a future release.
- **Qbaike connector**
A new Qbaike connector lets you look up corporate registry info in chat — fuzzy company search, basic info and change history, contact details, key personnel, shareholders, beneficial owners, and ultimate controllers.
- **MCP Apps protocol**
QoderWork now supports the MCP Apps message and context protocol, enabling connectors to deliver richer interactive UI and structured results.
- **MS365 enterprise mode**
Opt in to unlock organization-level permissions (Teams channels, directory, etc.). OneDrive authorization prompts also no longer pester you repeatedly — after a decline or timeout, QoderWork backs off automatically, and file uploads are more reliable overall.
**🔧 Improvements**
- **Cleaner connector cards**
Connector cards show only what matters; refresh behavior and bundled skills for installed connectors are now in sync.
- **Faster model list**
The model list now loads from a local cache — noticeably faster on startup and when switching. Model detail cards also support Markdown links, and off-peak discounts are clearer.
- **Lighter logout**
Sign-out is now non-blocking — the UI switches immediately while resources are released in the background.
**🐛 Fixes**
- Fixed popovers being unexpectedly dismissed when used inside a dropdown menu
- Fixed the image viewer close button having too small a hit area
- Fixed being stuck on the settings page after a redirect
- Fixed announcement banners being click-through to elements below
- Fixed lost attachments in multi-part messages and out-of-sync file state in the chat input
- Slack: fixed slash command reply updates and filename special-character handling
- WeCom: fixed missing error feedback when message sending fails
### Everyday Polish
General stability and quality-of-life improvements.
**🐛 Fixes**
- Fixed an occasional compatibility issue when using the DingTalk connector from Git Bash on Windows
### Manual Context Compression & Off-Peak Discounts
Context compression now supports manual triggering on top of the existing automatic mode — free up space whenever you want. Qwen3.7-Max and Qwen3.7-Plus also gain off-peak promotions for friendlier pricing.
**✨ New**
- **Manual Context Compression**
Beyond the existing automatic compression, a new compress button next to the usage indicator (right side of the input box) lets you compress chat history into a summary on demand.
- **Qwen3.7 Off-Peak Discounts**
Qwen3.7-Max and Qwen3.7-Plus now run off-peak promotions. Open the model selector to see the current campaign banner.
- **Reference a Browser Tab**
Use the "+" entry next to the input box to attach the current browser tab to your QoderWork input — no more copying and pasting URLs.
**🔧 Improvements**
- **Input draft preserved across tasks**
Switching between conversations no longer wipes unsent text in the input box.
**🐛 Fixes**
- Resolved various issues for a smoother daily experience
### Advanced Model Tier
The model selector now offers an Advanced tier between Ultimate and Standard, with credit multipliers shown next to each option for clearer cost-vs-capability choices. This release also adds a right-click editing menu and a shortcut guide, brings real-time voice transcription to the input box, and upgrades the browser connector to V2.
**✨ New**
- **Advanced tier in the model selector**
A new Advanced tier sits between Ultimate and Standard. Credit multipliers are now visible next to each tier, making cost-vs-capability trade-offs clear at a glance.
- **Input box right-click menu**
Right-click the input box to access cut, copy, paste, undo, and other edit actions.
- **Shortcut guide**
A new entry in the title bar lets you browse available keyboard shortcuts at any time.
- **MCP marketplace additions**
Two new industry plugins: 1688 Buyer Assistant and 1688 Seller Assistant.
**🔧 Improvements**
- **Real-time voice transcription**
Voice input now streams text into the input box as you speak — no waiting until you finish.
- **Browser connector V2**
The browser connector has been rebuilt on a new architecture for more stable and responsive connections.
**🐛 Fixes**
- Fixed AppShot permission and shortcut conflicts.
- Fixed pinned conversations not staying at the top in custom groups.
- Fixed older conversation history occasionally appearing blank.
- Fixed unexpected exits when closing or minimizing windows on Windows.
- Fixed several display issues with the Parchment theme and serif font mode.
### Everyday Polish
General stability and quality-of-life improvements.
**🐛 Fixes**
- Fixed occasional issues during app update and restart.
### Awareness Mode is here!
Awareness Mode is now available to everyone — QoderWork remembers your preferences, project conventions, and working context across sessions, getting better the more you use it.
**🎉 Awareness Mode**
A new way to work — the longer you use QoderWork, the more it feels like a partner who already knows you.
QoderWork now automatically captures your preferences, project structure, tool habits, and communication style, maintaining continuous memory across sessions. No more repeating background context — it already knows. Powered by a three-layer mechanism of memory, reflection, and skill self-evolution. In Settings you can choose between "automatic" and "manual" memory maintenance, working at your own pace.
**✨ New**
- **Reference tasks from the @ menu**
The @ panel now lets you reference existing tasks and scheduled tasks, making it easier to connect context across sessions.
- **Conversation width preference**
A new setting lets you choose between default and wide conversation layout — great for large screens.
- **New built-in expert plugins**
Two new plugins: Tech Services and Litigation Toolkit.
**🐛 Fixes**
- Resolved various issues for a smoother daily experience.
### Everyday Polish
General stability and quality-of-life improvements.
**🐛 Fixes**
- Fixed an issue where tasks could terminate unexpectedly during execution.
### Everyday Polish
General stability and quality-of-life improvements.
**🐛 Fixes**
- Fixed model list failing to load in certain environments.
### Everyday Polish
General stability and quality-of-life improvements.
**✨ New**
- **Custom grouping & sorting for conversations**
Group your conversation list by custom groups, workspace directory, or time — and switch between sort orders.
### Everyday Polish
General stability and quality-of-life improvements.
### New Plugin & Connectors
A new built-in Product Design plugin lands, three new industry connectors join the MCP marketplace, and conversation archiving gets refined.
**✨ New**
- **Product Design plugin**
A built-in expert plugin for product design scenarios, ready to use out of the box.
- **MCP marketplace additions**
Three new industry connectors — Amap Cloud Maps, Huayu Yuandian, and PKULaw.
- **Refined conversation archiving**
A smoother archive experience, now also covering bulk archiving of scheduled tasks — keep long-unused items tidied away in one move.
**🔧 Improvements**
- **Mount a whole plugin from the @ panel**
The @ panel now lets you bring in an entire expert plugin in one tap, instead of picking skills one by one.
- **Standalone toggle for the voice floating window**
The bottom-of-screen voice input window summoned in the background now has its own toggle in Settings.
**🐛 Fixes**
- Resolved various issues for a smoother daily experience.
### Everyday Polish
General stability and quality-of-life improvements.
### Windows Computer Use
Computer Use is now available on Windows — QoderWork can see your screen and operate applications, just like on macOS. Also in this release: Connectors join Skills and Plugins in a unified "Extensions" section in the sidebar.
**✨ New**
- **Windows Computer Use**
Enable it in Connectors and QoderWork can see your screen and interact with applications on Windows, helping you complete cross-app tasks.
**🔧 Improvements**
- **Unified Extensions section**
Connectors have been promoted from Settings into the sidebar, joining Plugins and Skills under one "Extensions" group. Card interactions and styling are now consistent across all three.
**🐛 Fixes**
- General stability and quality-of-life improvements.
### Enterprise Management
This release introduces a set of management and governance features for enterprise administrators, enabling organizations to adopt QoderWork at scale with unified control.
**✨ New**
- **IM Channel Access Control**
Admins can now govern which IM conversations are allowed to connect to QoderWork. Pair and authorize contacts or group chats individually—unauthorized sessions require admin approval before they can access QoderWork, keeping members safe from unwanted conversations while giving the organization controlled, on-demand IM access.
**🐛 Fixes**
- General stability improvements for a smoother overall experience.
### macOS Computer Use
Computer Use is now available by default on macOS — QoderWork can see your screen and interact with apps on your behalf. AppShot and voice polish are also live.
**✨ New**
- **macOS Computer Use**
Enable it in Connectors and QoderWork gains the ability to see your screen and operate applications, helping you get cross-app tasks done.
- **AppShot**
Capture the current app's screen in one click — it lands right in your QoderWork input box, giving QoderWork a clear picture of what you're working on.
- **Voice polish**
Spoken input is now auto-refined into smoother written text. A first-launch guide helps you get started.
**🐛 Fixes**
- General stability and quality-of-life improvements
### Everyday Polish
General stability and quality-of-life improvements.
### Qwen3.7-Max
New model, limited-time promotional rate.
**✨ New**
- **Qwen3.7-Max**
Now available in the model selector — try it at a limited-time promotional rate.
### Everyday Polish
General stability and quality-of-life improvements.
### Everyday Polish
Fixed Dock icon glitches after macOS updates.
### Writing Desk and Slides Desk are here!
Writing Desk and Slides Desk are now live — from a rough idea to a polished post, from a few lines of prompt to a ready-to-present deck, all in one place inside QoderWork.

**🎉 Writing Desk**
Introducing Writing Desk. Turn ideas into professional writing — no more staring at the blank page.
Switch to "Writing" mode in the input box and tell it what you need — a blog post, a weekly update, a product doc, an email — QoderWork plans the structure, drafts the content, and shows it in a live preview on the right. Pick a tone of voice (professional, friendly, energetic, and more), tweak paragraphs, rewrite sentences, adjust styling. Need to look things up, pull data, or insert charts? It can call MCP tools right inside the workflow. When you're done, export in one click or keep iterating.
For example, a marketing teammate writing a product launch post can switch to Writing mode, describe the key points and audience, get a clean draft in seconds, rewrite it in a friendlier tone, fix up the heading hierarchy — and the post is ready.
**🎉 Slides Desk**
Introducing Slides Desk. One sentence in, a presentation-ready deck out.
Switch to "Slides" mode in the input box, describe the topic and audience, and QoderWork plans the pages, generates the content, applies a coordinated visual template, and previews every slide on the right. Browse templates, preview each draft slide, confirm, and the full deck is generated. Once ready, present in fullscreen or export to standalone HTML so you can run it from any room.
For example, when you're suddenly asked to give a talk: switch to Slides mode, describe the topic and outline, get a complete deck in seconds with a live preview, pick a template you like, and hit fullscreen — you're ready to go.
**🐛 Fixes**
- General stability improvements for a smoother day-to-day experience
### Everyday Polish
General stability and quality-of-life improvements.
### Design Desk and Voice Input are here!
Design Desk is here — describe your idea, get a real deliverable. Not just for designers: anyone can go from idea to professional design to runnable code, all in one place. Voice Input launches alongside — just say it and it gets done.
**🎉 Design Desk**
Introducing Design Desk. Ideas become products. Design becomes code.

Switch to "Design" mode in the input box, describe what you need — "build a SaaS analytics dashboard" — and QoderWork plans the page structure, generates the full interface, and shows it in a live canvas preview on the right. Choose from 100+ style references including Apple, Stripe, and Linear. Toggle between wireframe and high-fidelity. Use Ant Design, shadcn/ui, or other component libraries. After generation, fine-tune colors, spacing, radius, and light/dark theme — then export or hand off to Cursor, Zed, or any dev tool you use.
For example, a product manager who needs a quick prototype can switch to Design mode, say "task management dashboard in Linear style", get a high-fidelity preview in seconds, tweak the colors, and export — no Figma needed.
**✨ New**
***Voice input: talk instead of type***
Press the shortcut to start talking — transcription fills the input box automatically. Works when you're walking, between meetings, or when your hands are busy. Supports Fn key, custom keys, and key combinations. Configure it your way in Settings.
**🐛 Fixes**
- Fixed Dock icon display issues after updating on macOS, and unexpected main window defocus on launch
- General stability improvements
### Message Recall
Press ↑/↓ in the chat input to cycle through your previous messages — just like a terminal.
**✨ New**
- **Arrow-key message recall**
Press ↑ or ↓ in the input box to instantly recall messages you've sent in the current conversation. Edit and resend without retyping.
**🐛 Fixes**
- Fixed in-chat search accuracy, IM channel sync issues, and other daily-use annoyances
- Resolved several crashes for improved overall stability
### Everyday Polish
General stability and quality-of-life improvements.
### Network Proxy
QoderWork now supports global network proxy configuration — use it behind corporate firewalls or restricted networks without issues. You can also search across all conversations to quickly locate past tasks.
**✨ New**
- **Network proxy**
Configure a global proxy in Settings to route all network traffic through it — works behind corporate firewalls and restricted environments.
- **Global task search**
Search across all your conversations to quickly find past tasks and messages.
**🐛 Fixes**
- Resolved various issues including HTML preview rendering, glass theme display, and credit usage icon visibility.
### Task Groups
Conversations can now be organized into groups — managing a busy task list just got easier. This release also addresses a number of quality-of-life issues.
**✨ New**
- **Task groups**
Organize your conversations into groups, making it easier to find what you need when tasks pile up.
**🐛 Fixes**
- Resolved various issues including sidebar layout and Windows upgrade stability.
### Everyday Polish
General stability and quality-of-life improvements.
### DingTalk Workspace CLI
QoderWork now connects to the DingTalk Workspace CLI — manage todos, reports, attendance, and 10+ modules in natural conversation.
**✨ New**
- **DingTalk Workspace CLI (DWS)**
Enable the DingTalk connector and use natural language to manage todos, daily reports, attendance, calendar, approvals, and more. No more navigating pages and clicking buttons — just say what you need.

**🔧 Improvements**
- **Guided connector setup** Connectors now offer a step-by-step setup flow with automatic authentication — faster onboarding, fewer manual steps.
- **Input bar refinements** Improved connector grouping and behavior in the chat input.
**🐛 Fixes**
- Resolved various issues related to conversation cancellation, connector display, IM channel list, and overall page stability.
### Expert Kits: Now Available
The past few releases focused on ongoing stability and experience improvements. With 0.3.15, we're introducing Expert Kits — 10 built-in kits covering legal, finance, contract management, product management and more, turning AI from a generalist into a domain expert. Custom kit creation and sharing are also supported.

Expert Kits don't just connect AI to tools — they give AI professional-grade capabilities for specific roles.
**✨ New**
- **10 Built-in Kits at Launch**
Covering finance, legal, marketing, and more — ready to use out of the box.
Multiple kits can be used in a single conversation. For example, combine "Contract Management" and "Corporate Legal" to handle legal review and contract generation in the same workflow.
| Kit | Description |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Product Management | PRD writing, user story breakdown, competitive analysis, requirement prioritization, user feedback analysis, roadmap updates, product metrics review |
| Corporate Legal | Draft legal documents, generate corporate resolutions, case research with win-rate analysis, compliance review, risk assessment |
| Contract Management | Contract review, contract drafting, redline comparison, NDA quick screening, statute lookup, contract ledger reminders |
| Corporate Finance & Tax | Financial analysis, bookkeeping vouchers, budget analysis, VAT management, annual settlement, internal audit, financial statements, month-end closing |
| Consulting Delivery | Desk research, interview notes, framework design, report writing, benchmarking, weekly reports, CEO briefings |
| Marketing | Marketing copy, ad compliance, competitor tracking, campaign planning, social media trending, SEO optimization, campaign analytics, brand consistency review |
| Investment Research | In-depth reports, industry research, annual report analysis, earnings flash reviews, research notes, morning meeting briefs, research summaries, comparable company analysis |
| Investment Banking | IPO prospectus drafting, M\&A reports, bond offering memorandums, exchange inquiry responses, roadshow materials, financial modeling |
| Private Equity | Project screening, due diligence checklists, term sheet review, investment committee memos, return modeling, exit analysis |
| Wealth Management | Market briefings, asset allocation, fund analysis, client reporting, financial planning, tax planning |
### Everyday Improvements
Versions 0.3.8 through 0.3.11 bring a wide range of everyday usability improvements.
🔧 Improvements
- Settings Page
Refined layout and updated copy
🐛 Fixes
- Fixed various issues affecting daily usage
- Fixed several Windows platform compatibility issues
- Additional stability improvements
### Desktop Control from IM
This release bridges IM and desktop — control your tasks right from your IM conversations, with new capabilities like Generative UI.
**✨ New**
- **IM Binding**
Use /bind in any IM conversation to connect to an active desktop task — interact with it remotely, anytime, anywhere. The desktop UI shows binding status in real time, and /unbind disconnects when you're done.
- **Generative UI (experimental)**
Agents can now go beyond text — they can render interactive components like buttons and tables right in the conversation. To try it, flip its toggle under Experimental Features in Settings.
- **Context usage indicator**
A new indicator below the input box shows context usage — when it's full, start a new task to save credits.

**🔧 Improvements**
- **Simplified DingTalk bot setup**
You can now scan a QR code directly in the IM channel to create and configure the DingTalk bot — faster and easier than before.
**🐛 Fixes**
- Fixed UI issues including thinking-mode scroll jumping, Windows desktop shortcut loss, and image path display
- Fixed functional issues with skill market sharing/installation and IM card status sync
- Fixed MCP authentication and CJK URL auto-linking
- Reduced idle resource usage
### Skill Sharing
This release introduces Skill Sharing, WeCom bot integration, and a Microsoft 365 connector, along with on-demand MCP tool loading and a redesigned browser extension.
**✨ New**
- **Skill Sharing**
Share skills you’ve created directly with others—recipients can install them with a single click.
- **WeCom Bot**
A new WeCom channel lets you chat with QoderWork right inside WeCom.
- **Microsoft 365 Connector**
Connect to data and services across the Microsoft 365 ecosystem.
**🔧 Improvements**
- **On-Demand MCP Loading**
MCP tools now load on demand instead of all at once, resulting in faster startup times.
- **Browser Extension Upgrade**
The browser extension has been completely redesigned for a smoother experience and improved stability.
- DingTalk and Feishu IM now support streaming output
**🐛 Fixes**
- Fixed interaction issues including message attachments not opening on click and Command+F clearing search text
- Fixed functional issues with skill installation and scheduled task history display
- Fixed various issues in Feishu and DingTalk IM
### Custom Shortcuts & Browser Experience
Versions 0.3.1 through 0.3.4 focused on stability and usability improvements. Building on that, this release makes daily use smoother — customizable shortcuts, better browser experiences, and additional improvements.
**✨ New**
- **Customizable shortcuts**
You can now configure keyboard shortcuts for sending messages and line breaks in Settings — use Enter to send or to insert a new line, your choice.
- **Multi-session browser**
Multiple conversations can now use the browser tool simultaneously, each working independently.
- **Browser extension officially launched**
The browser extension is now live on the Chrome Web Store with a streamlined installation experience. We recommend uninstalling the old extension and installing the official release for the best experience.
- **HTML preview external links**
Links in HTML previews now open directly in your system browser.
**🔧 Improvements & Fixes**
- Refined theme details for better visual comfort
- Resolved various issues for a smoother daily experience
### IM Channels
QoderWork is no longer just waiting on your desktop. This release launches IM Channels — talk to QoderWork right inside DingTalk, Feishu, or WeChat, wherever your day already happens.
**🎉 IM Channels**
Open Configuration, set up your bot, and find it in your favorite chat app — that's it. Everything you've configured on the desktop carries over — your Skills, MCP, Connectors, all of it.
- Works with DingTalk, Feishu (Lark), and WeChat
- DingTalk and Feishu support both direct messages and group chats (just @mention the bot); WeChat supports direct messages
- Pairing mode is on by default — only direct messages and group chats you've authorized can interact with your bot

Beyond that, this release brings a massive round of user experience improvements.
### Settings Refresh
This release polishes the Settings page and connector interactions, and adds a changelog entry point. A round of stability and display fixes are also included.
**🔧 Improvements**
- **Settings & connector interaction polish**
Refined the Settings layout and connector configuration flow for a smoother experience.
- **Changelog entry point**
Added a changelog entry point so you can check what's new at any time.
**🐛 Fixes**
- Fixed a number of issues affecting daily usage.
### HTML Rendering
HTML now renders in-app — preview your web pages right in the conversation. This release also polishes the usage panel and includes a round of bug fixes.
**✨ New**
- **HTML rendering**
HTML files now render in-app, so you can see your web pages take shape without switching to a browser.
**🔧 Improvements**
- **Usage panel polish**
Polished the usage overview layout — remaining credits are now easy to spot at a glance.
**🐛 Fixes**
- Fixed a number of issues affecting daily usage, including duplicate messages, update notification popups, Settings dialog behavior, and image display.
### Patch
Fixed a browser extension compatibility issue.
### Bug Fixes
Fixed a number of bugs affecting daily usage.
### Scheduled Tasks
🎉 Scheduled Tasks are live.
Let QoderWork handle recurring tasks for you — all managed from a dedicated sidebar. This release also introduces macOS Connectors and math formula rendering.
**✨ New**
- **Scheduled Tasks**
Create them manually from the sidebar, or tell QoderWork in conversation and it sets them up for you. Tasks are automatically grouped for easy management, with execution results and history always accessible.
- **macOS Connectors**
Enable them in Settings. QoderWork can read and write your Notes, Calendar, Reminders, Mail, and Contacts — no extra setup required.
- **Math formula rendering**
LaTeX math formulas now render properly.
### Browser Connector
QoderWork introduces the Browser Connector — a zero-dependency, zero-config way to connect your real browser, completely replacing complex browser MCP setups.
**✨ New Features**
- **Browser Connector**
Seamlessly integrates via a browser extension with no extra dependencies. Reuses your real browser so cookies and login sessions are preserved out of the box. Carries your authentic browser fingerprint to avoid bot detection. Lets you manually select which tabs to connect, giving you precise control over what the AI can access. Click the setup link in the chat box and follow the guide to load the extension.

### Bug Fixes
Fixed a few issues affecting daily usage.
**🐛 Fixes**
- Fixed "Add to Chat" quoted content being sent to the AI as unreadable raw tokens instead of properly formatted text
- Fixed an occasional blank screen when switching between tasks
- Fixed the "Open with" menu for output files showing no available applications
### Direct Connect
The Browser tool now supports Plugin Mode — flip the toggle to connect to your existing browser.
**🔧 Improvements**
- **Browser Plugin Mode**
Turn on Plugin Mode to connect to your existing browser session — complete with all your logins and cookies.
### Bug Fixes
Fixed a number of issues affecting daily usage, including QuickPick input, message sending, window display, and Windows platform compatibility.
### Safer File Ops
A small but meaningful update that makes file handling safer and fixes a model list loading issue.
**🔧 Improvements**
- **Safer file operations**
File handling is now more cautious and controlled, reducing the risk of unintended changes.
**🐛 Fixes**
- Fixed an issue where the model list could fail to load.
### The Little Things
A round of detail-level polish and bug fixes to make everyday use more reliable.
**🔧 Improvements**
- **Expanded QoFounder contact fields**
A new "Other contact" field lets you share additional ways to reach you.
- **File context menu**
Right-click any file card to open it, reveal it in your file manager, copy its path, or choose which app to open it with.
**🐛 Fixes**
- Fixed a race condition where the first message in a new task would occasionally not appear.
- Various other fixes including local session recovery, feedback submission, and startup stability.
### Built-in create-skill
This release adds a handy new built-in skill: you can now create your own skills right in conversation. A few stability bugs have been fixed along the way.
**✨ New**
- **Built-in create-skill**
Create custom skills directly in conversation — no manual file setup needed.
**🐛 Fixes**
- Fixed an issue where conversation history could fail to restore in certain scenarios
- Fixed a potential crash on startup
- Fixed some UI cards not displaying correctly after a page refresh
### Stability & Polish
The last release introduced a number of new features — this one is all about making them rock-solid. Several bugs affecting daily usage have been fixed.
**🐛 Fixes**
- Fixed an issue where trial credits were not correctly granted to new users
- Fixed Agent question cards losing their layout after a page refresh
- Fixed stale error banners persisting after switching accounts
- Fixed occasional failures in conversation title generation
### Cross-Platform Polish
This release focuses on cross-platform polish and everyday quality-of-life improvements. Smarter architecture detection, more reliable MCP diagnostics, and a batch of Windows fixes.
**✨ New**
- Language switcher on login
A new toggle on the login page lets you switch between Chinese and English.
- Smart architecture detection
QoderWork now automatically detects your system architecture on first launch and guides you to the correct installer.
**🔧 Improvements**
- Better MCP diagnostics
QoderWork now prompts you to shut down the VM before running MCP diagnostics, so issues can be diagnosed directly on the host machine.
**🐛 Fixes**
- Fixed an issue where content pasted from rich-text editors like Word was incorrectly recognized as an image
- Fixed an issue where messages could get mixed up when sending tasks in rapid succession
- Fixed skill examples failing to load
- Windows: Fixed close button behavior (now minimizes to tray), tray icon, context menu, and other platform-specific issues
### Experience, Refined
This release focuses on polish rather than big features — but you'll notice it feels smoother. We've also revamped how conversation titles are generated.
**✨ New**
- Smarter conversation titles
Auto-generated titles are now more accurate and distinctive, making it easier to find past conversations.
**🐛 Fixes**
- Resolved several issues that could occur during startup
- Fixed an issue where Cmd+W failed to close the window in conversation history on macOS
- Various other minor fixes and improvements
### QoderWork just got a major upgrade
This is the biggest update in QoderWork's history. We're officially launching on Windows, and shipping VM sandbox support on both macOS and Windows simultaneously — starting today, whether you're on macOS or Windows, QoderWork can handle your tasks in a secure, isolated environment.
**🎉 Windows Is Here**
QoderWork is no longer macOS-only. After extensive development and testing, we're bringing the full QoderWork experience to Windows — natively built, deeply optimized, and ready to go out of the box.
Supported platforms: macOS 14+ | Windows 10+
**🎉 VM Sandbox — Launching on Both Platforms**
Also headlining this release: VM sandbox support ships on macOS and Windows at the same time, with full platform coverage from day one.
Why you'll love it:
- Pre-configured environment, zero setup: Core runtime dependencies ship built-in, eliminating tedious configuration and making task execution faster than ever.
- Sandboxed isolation, clean execution: Tasks run in complete isolation from your local environment — no dependency conflicts, no environment pollution, and no more "it works on my machine."
- Local processing, total control: Your files stay on your machine. Sensitive data never leaves your device, ensuring privacy and security by design.
**✨ What's New**
**Skills Marketplace**
A brand-new skill ecosystem is now live, making QoderWork's capabilities infinitely extensible.
- Browse and search the full skill catalog
- One-click install / uninstall — ready to use instantly
- Preview demo scenarios for inspiration
**Model Tiers**
Introducing Standard and Flagship mode switching — choose what works best for you. Standard mode is cost-effective, while Flagship mode delivers the best possible results.
**MCP Enhancements**
Configure custom MCP servers — set server types, startup commands, and environment variables to match your setup
### Hello, World!
Hey, I'm QoderWork! Nice to meet you.
As the newest member of the Qoder family, I bring Qoder's Agent capabilities beyond coding into your everyday work. I'm a desktop AI assistant — simply describe what you need, and I'll take care of the rest.
Here's what we can accomplish together:
- Describe Goals, Deliver Results: I'm not just a chatbot. Tell me what you want to achieve, and I'll autonomously plan, break down tasks, execute step by step, and deliver the final output. The entire process is fully transparent, so you stay in control.
- File Organization & Data Processing: Whether it's auto-sorting a messy project folder, organizing a photo library by date and location, or cleaning and analyzing CSV/Excel data to produce visual reports — just say the word.
- All-Around Document Creator: From Word reports, PowerPoint presentations, and Excel spreadsheets to Markdown documentation and professional PDFs — I can generate them from scratch with proper formatting and polished layouts.
- Research & Information Synthesis: I can search the web for the latest information, aggregate multi-source data, extract key insights, and help you quickly produce well-structured research reports.
- Extensible Capabilities, Limitless Scenarios: I come with built-in MCP integrations (GitHub, Amap, browser automation, and more) and support custom Skills, allowing you to build your own intelligent workflows for virtually any scenario.
- Local & Secure: I run locally on your device and never access any files without your explicit permission. Your data stays in your hands — always safe and under your control.
And there's so much more I can do — from automated competitive analysis reports and comprehensive travel planning, to end-to-end academic research support. If you can describe it, I can deliver it.
The current version supports macOS, with Windows coming soon. Sign in with your Qoder account — Credits are shared across the platform.
Let's explore smarter ways of working together and embark on this exciting AI-powered journey!
# QoderWake Release Notes
> Release history for QoderWake.
This page lists the release history for QoderWake, with the newest version first.
### Console Chat Upgrades and More Flexible Tool Approvals
### Improvements
- **Console Chat**: Pasted long text folds into a removable card, long messages collapse by default, and a back-to-latest button is added.
- **Tool Approval**: Approval requests pop up on any Console page, remote conversations support direct approval, and always-allow stops repeat prompts within a task.
- **Instant Settings**: Changes to skills, connectors, or project settings take effect on the next message without interrupting the ongoing conversation.
### Bug Fixes
- Fixed an issue where stopping a reply left the conversation stuck running and generated content disappeared after refresh.
- Fixed an issue where a DingTalk bot with invalid credentials stayed connecting indefinitely; a clear failed status with guidance now shows.
### DingTalk QR Code Setup and Clear Quota-Exhausted Notices
### Improvements
- **DingTalk QR Setup**: Configure a DingTalk bot channel by scanning a QR code to auto-fill credentials, with manual entry still available anytime.
- **Quota Exhausted Alerts**: Sessions, workflow run details, and IM replies now clearly report exhausted quota and guide you to upgrade, without retrying.
- **Session Catch-Up**: Switching back to a running task now loads all messages produced while away at once, without duplicate bubbles or lingering cursors.
### Bug Fixes
- Fixed scheduled tasks being wrongly marked failed or stuck in running after a restart; interrupted tasks now resume and complete normally.
- Fixed IM bots sending duplicate replies to messages they had already answered after a session was restored following a restart.
- Fixed noticeable product-wide sluggishness with very large local history data; session detail pages and similar views now load much faster.
### Direct Connector Links and Smoother Console Sessions
### Improvements
- **Connector Link Navigation**: Connector links in conversations now open the installed connector's settings directly, and legacy addresses redirect automatically.
- **IM Channel Setup**: Saving an IM bot configuration now completes immediately, and certificate issues on enterprise networks show clear recovery guidance.
### Bug Fixes
- Fixed an issue where switching conversations reloaded the whole console page, so session switching now updates in place.
- Fixed an issue where the console defaulted to English on Chinese macOS and Windows, so it now opens in the system language.
- Fixed an issue where image processing and terminal features failed in the macOS installer edition, so both now work normally.
- Fixed an issue where automated tasks received triggers but stayed stuck running after a background service restart, so they now execute properly.
### Connector Market Arrives with Group Collaboration Fixes
### What's New
- **Connector Market**: Browse featured connectors in the new Market tab of the console Connectors page, with one-click install to a Waker plus authorization and enable/disable management.
### Bug Fixes
- Fixed an issue where image questions in IM groups could get no reply; a clear notice now appears when message reading fails.
- Fixed an issue where switching accounts on one device could lose IM bot settings and pairings; configs now restore per account.
- Fixed an issue where console sessions still started with auto-selected models after saving a model preference; saved preferences now apply.
- Fixed an issue where team group tasks could repeatedly fail or stay stuck in a running state for a long time.
### Claim Model Credits in the Upgraded Usage Panel
### Improvements
- **Credits Usage View**: The console usage panel now offers a Credits view with model promotion credit progress, remaining balance, end date, and details link.
- **One-Click Credit Claiming**: Claim model credit promotions in the console usage panel with instant balance refresh; unavailable promotions appear disabled, and failed claims support retry.
- **Benefit Notification Card**: A console card appears when a claimable Qwen3.8-Max limited-time benefit is available, opening the usage panel to claim; dismissed cards stay hidden.
### Bug Fixes
- Fixed authorization errors when loading promotion credits in the usage panel triggering a console re-login prompt.
### Sign-In Protection and One-Click Updates
### Improvements
- **One-Click Updates**: Checking for updates in Settings now downloads and installs new versions directly, and the restart card activates them in one click.
- **Remote Sign-In Recovery**: Self-hosted deployments can optionally allow designated remote console pages to recover sign-in or sign out; disabled by default.
- **Sign-In Protection**: Account sign-in is now better protected against unexpected sign-outs, and previous sign-in states expire immediately after switching accounts.
### Bug Fixes
- Fixed an issue where the page still showed a signed-out state after re-signing in, so the page now recovers once sign-in completes.
- Fixed an issue where some local features stopped working in self-hosted environments after sign-in protection was enabled.
### Q\&A Specialist Officially Released
### What's New
- **Q\&A Specialist Officially Released**: The Q\&A Specialist is now available, answering questions in DingTalk and Feishu group chats based on your knowledge bases and designated experts. A three-step quickstart gets it running, and experts can correct answers directly in the chat to update knowledge in real time with undo support.
### Improvements
- **Chat Attachments**: Drag or paste files and images into the console chat input to add attachments in direct and group conversations.
- **Task Board**: The task board offers one place to review task progress and act on pending approvals in the approval workspace.
### Bug Fixes
- Fixed an issue where session and task statuses in the history panel stayed in progress, so they now refresh within seconds of completion.
### Everyday Experience and Reliability Improvements
### Improvements
- **File Attachments**: Drag or paste local files and images directly into single and group chat inputs, with clear per-file failure feedback.
- **Upgrade Suggestions**: Console and CLI now show a version upgrade suggestion when your installed QoderWake version is outdated.
### Bug Fixes
- Fixed group chat messages briefly appearing duplicated after sending, and tasks awaiting answers being misjudged as failed or stuck.
- Fixed conversation and automation task lists staying stuck on running instead of refreshing status promptly after completion.
### IM Channels Recover Automatically After Availability Changes
### Improvements
- **IM Channel Recovery**: Enabled IM channels can now recover after availability changes, reducing unexpected interruptions.
### Streamline DingTalk Pairing and Channel Management
### Improvements
- **Batch Pairing Setup**: Select multiple conversations in the add-pairing dialog and apply one Waker, model, and working directory together.
- **Pending Request Actions**: Batch-approve or ignore multiple pending pairing requests on the current page, each sharing one Waker, model, and directory.
- **Message Suffix**: Append an editable suffix to outbound replies and narration on the DingTalk personal-account channel, on by default.
### Smoother issue feedback
### Improvements
- **Issue Feedback**: The feedback dialog in Console now opens instantly with an editable form, so you no longer wait on a full-screen loading state; runtime details and the automatic screenshot are gathered in the background, and a contact email you have already filled in is kept instead of being overwritten by results that arrive later.
### Steadier logins, session status, and IM page polish
### Improvements
- **IM Page Copy**: English wording across the IM pages now reads more naturally and idiomatically.
- **New Project Dialog**: Opening the New Project dialog from within pairing, approval, or edit dialogs now stays clickable and editable, with focus returning correctly after it closes.
- **Paired List Layout**: Actions in the public IM paired list now stay neatly aligned across languages.
### Bug Fixes
- Fixed login sometimes staying stuck; a single login click now recovers, and background and automation connections reconnect automatically.
- Fixed paired sessions using older DingTalk bots being hidden from the public IM paired list; they now appear correctly.
- Fixed finished remote-control sessions still showing as Running; reopening the session or the Session History list now shows the correct status.
### Experience polish: responsive card layouts, DingTalk channel guidance, and clearer macOS quit prompts
### Improvements
- **Responsive Card Layouts Across Management Pages**: Card lists on the management pages now adapt to the available screen width, showing more cards per row on wide and ultra-wide displays and staying tidy on narrow screens. This covers My Wakers, My Groups, WakerFlow, Public Projects, Knowledge Bases, and the Approval Workbench.
- **Card Type Guidance for DingTalk Bot Channels**: When setting up a DingTalk bot channel, the card type option now explains the difference between the standard card and AI card modes and links to the bot management console, so administrators can choose the right mode and reach the settings directly.
- **Clearer Quit and Restart Confirmation on macOS**: On macOS, the quit and restart confirmation now reflects only sessions that are actually busy, so idle sessions no longer raise an unnecessary interruption warning. The Chinese interface also renames "Trigger tasks" to "自动任务" for clarity.
### Clearer prompts, responsive Console layouts, and quit/restart stability
### Improvements
- **Sensitive-Content Message**: When a conversation is blocked for sensitive content, a clear localized message now appears suggesting a model switch or a new session—no more cryptic upstream errors.
- **DingTalk Pairing**: Adding a DingTalk pairing now uses a single search box that finds contacts or group chats by name or ID, with a simple toggle between single chat and group chat.
- **Responsive Card Layouts**: My Wakers, My Groups, Workflows, Public Projects, and Knowledge Notebooks pages now adapt to the screen width, showing more columns on wide screens.
- **Login Stability**: The Console no longer triggers a logout on temporary network hiccups, and browser sessions stay valid across a client restart or upgrade (until an explicit logout or session expiry).
### Bug Fixes
- Fixed an issue where quitting or restarting could hang for a long time if a background task stalled.
- Fixed an issue on Windows where skills with special line endings could prevent sessions from starting.
- Fixed "Launch at Login" on Windows desktop so it works reliably and no longer registers itself multiple times.
### Unified multi-instance management and access policies for IM channel bots
### Improvements
- **Multi-instance bot management**: Weixin, WeCom bots, and QQ bots now use the same grouped multi-instance management as DingTalk and Feishu. You can add, identify, and independently manage multiple bots of the same type, with instance counts, expand/collapse, and a more/collapse control once there are over 5 instances. Each instance can be edited, enabled or disabled, and deleted on its own.
- **Feishu bot shown by default**: The Feishu bot channel now appears in the console by default — its group is shown when configured, and the add entry is shown when it isn't.
- **Paired and open access policies**: Weixin, WeCom bots, and QQ bots now support two access policies. Open mode responds through a default Waker, while paired mode uses the unified pairing approval, manual add, and session management flow so a single bot can dispatch to multiple Wakers by conversation.
- **Optional working directory**: When configuring pairing (approval, manual add, pairing code, or session edit) or an open-mode bot, the working directory is now optional; leaving it empty uses the responding Waker's default IM working directory. Open mode only requires choosing the default responding Waker, with model and working directory as optional overrides.
- **Safer Waker deletion**: Deleting a Waker that is still the default delivery target of an open-mode public bot is now blocked. The affected channels are listed so you can rebind, switch, or remove them first, avoiding an unusable public connection.
### Bug Fixes
- Fixed an issue where replies from public multi-instance bots in open mode could fail to be delivered.
### New Qwen3.8-Max-Preview off-peak option, richer model descriptions, and reliability fixes
### Improvements
- **Qwen3.8-Max-Preview**: The new Qwen3.8-Max-Preview model is now selectable in the model picker, and it joins the off-peak lineup at a deep off-peak discount so long-running tasks cost far less during off-peak hours.
- **Clearer Model Descriptions**: Model hover cards now show curated, model-specific descriptions for more models, including Qwen3.8-Max-Preview, DeepSeek-V4, GLM-5.2, Kimi, and MiniMax.
### Bug Fixes
- Fixed running sessions with new activity not showing an unread indicator in the task list, so the unread count always maps to a session that can be opened.
- Fixed session creation sometimes failing with a "Daemon is reconnecting" message caused by a stuck background connection; the daemon now recovers on its own.
### Realtime Unread Badges, Workflow Studio Status Cleanup, and IM Channel Fixes
### Improvements
- **Realtime Unread Badges**: Chat list entries, Waker and group badges, and Session History unread counts now update in real time and stay in sync across devices.
- **Clearer Workflow Studio Run Status**: When a WakerFlow run fails or is stopped, employees, actions, sub-flow calls, and awaiting-input nodes no longer stay stuck as "dispatching" or "running," making it clear at a glance when a run has actually ended.
- **Session History Icon Polish**: A session wrapping up normally no longer briefly flashes a red error icon.
- **Smoother Group Composer and Navigation**: Sending a message in a group now clears the draft, attachments, and selected members right away and restores them if the send fails, and switching between past sessions in the same group stays stable without flashing or reshuffling the list.
- **Windows Install and Authorize**: On Chinese Windows, the DWS CLI "Install and Authorize" failure message is now readable instead of garbled, and finishing the install no longer shows a false failure.
### Bug Fixes
- Fixed a DingTalk direct-message issue where sent messages could be routed back to the sender's own account; the "self" account can no longer be added as a direct-message target, and older self entries no longer trigger tasks.
- Fixed an IM channel issue where saving settings could drop a channel's existing Waker binding or routing, so inbound messages now reach the right Waker.
### More Reliable DingTalk and Feishu Group Replies
### Improvements
- **DingTalk Group Replies**: When you @mention the bot in a DingTalk group, its reply now @notifies you directly and highlights your name.
- **Cleaner Reply Cards**: The bot no longer pops an empty "..." card first, and it won't send two reminder cards for the same question.
### Bug Fixes
- Fixed DingTalk, Feishu, and other IM channel replies being lost, stuck on an empty "processing" card, duplicated for the same message, or skipped when a question arrived late.
### IM-Style Navigation, Skill Marketplace Search, and Team Group Collaboration
### Improvements
- **IM-Style Navigation**: Console app shell redesigned with two-level IM-style rail, resizable Chat sidebar, and refined management page button hierarchy
- **Skill Marketplace**: Keyword search, category filtering, sorting, pagination, and rich-text SKILL.md editing with version history for installed skills
- **Global Task Board**: Pending WakerFlow approval cards visible on the unified task board
- **Team Group Collaboration**: Structured multi-step planning with dynamic replanning; real-time progress indicators show member activity in team groups
- **IM Channel Management**: Multi-target binding lets one bot route messages to different Wakers or groups by conversation; per-Waker page adds session filtering, inline editing, and pairing code generation
- **Global Settings**: Language, theme, auto-launch, network diagnostics, and device environment management in a dedicated settings page
### Bug Fixes
- Fixed MCP connectors with static header authentication failing to connect due to expired or missing OAuth tokens
### Smoother WakerFlow status, clearer device management, and steadier DingTalk connections
### Improvements
- **WakerFlow**: Node status now shows readable text instead of only color dots, with final states displayed as "Completed / Failed", and workflow titles you renamed are no longer overwritten by model-generated names.
- **Device Management**: Eligible device cards (offline or unknown non-current devices) now offer a "Remove Device" action.
### Bug Fixes
- Fixed DingTalk bot connections that could appear falsely online and fail to recover after dropping; connections are now more stable and reconnect automatically.
### Global IM channels with multi-target routing, plus Console experience upgrades
### What's New
- **Global IM Channel and Multi-Target Routing**: An IM bot is now set up as a global channel and managed from the redesigned public IM pairing page, so a single bot can route different chats or groups to different Wakers or Team group chats. When approving or manually adding a pairing you can choose its delivery target, and the paired list lets you view, edit, enable or disable, and delete each pairing with search and status filters.
### Improvements
- **WakerFlow Quick Actions**: The WakerFlow detail chat now offers one-tap quick actions—"Test Run" (available when the flow has a script) and "Diagnose Recent Run" (shown when a recent run exists)—so you can try a flow or troubleshoot its latest run without leaving the page.
- **Inline Artifact Card**: Direct chat now shows a compact artifact card right below the reply that produced it (file/code-change counts, expand or collapse, open), so you no longer need to open the "Current Task" panel first.
- **Fullscreen and Detail Dialogs**: Fullscreen dialogs (such as memory version management and Skill details) now fill the browser viewport and follow viewport resizing, and the "Role Template Details" drawer on the create-employee page scrolls independently without moving the background page.
### Bug Fixes
- Fixed the final part of an answer sometimes appearing only after switching conversations or refreshing, especially when the window was not focused; a reply now shows in full as soon as it finishes.
### Automation session recovery, plan retry, and model runtime tuning
### Improvements
- **Model Runtime Tuning**: In both direct and group model selectors, you can now open an Edit entry on the active model to adjust options such as its context window and thinking mode. In a group, the settings you save actually take effect for the current group conversation, instead of only being shown.
- **Clearer Group Task List**: The task list on a group's detail page now shows each task's step number, sorts tasks by step and then by plan order, and keeps status labels on a single line in your Console language.
- **One-Click Plan Recovery**: When a group's plan generation fails, it retries once automatically. If it still fails, the plan card gives you a "recreate plan" button so you can start over without losing the conversation, and a failed or cancelled plan no longer swallows the next message you send.
- **More Reliable Mark-All-Read**: When you mark all read on a Waker or group, the unread badge only clears after every remote session has actually advanced, and stale unread notifications are briefly ignored so the unread you just cleared isn't refilled by outdated data.
- **Steadier Automation Runs**: When an automation task stays silent in the background for a long time, gets stuck on a tool call, or its background service restarts, it now tries to recover on its own instead of failing early. Sessions that were reset in the background or ended normally also report a stopped state, so Console no longer keeps showing them as running.
- **More Reliable Install and Sandbox Deploy**: Installation and sandbox deployment now retry transient network errors while staying compatible with older environments, and write each file atomically so a failed download can no longer leave a broken, partial file behind. The installer also picks the correct QoderWake package on more complex release manifests.
### Bug Fixes
- Fixed the automation task entry and automation history tab occasionally disappearing in local Waker conversations; they now stay visible whenever you are in a local Waker session.
- Fixed valid images under 2 MB being rejected on avatar upload because the size was checked after encoding; the limit now applies to the original file you choose.
### WakerFlow is officially released , API session continuity, and team Plan-stage collaboration
### What's New
- **WakerFlow Released**: The WakerFlow workflow studio is now available. Run buttons open a parameter configuration dialog, and execution records refresh automatically when you open the tab.
### Improvements
- **API Trigger Session Continuity**: A new `wakeSessionUniqueId` parameter lets you route multiple API trigger calls to the same automation session with sequential execution.
- **Smoother Agent Execution**: Agent now enters planning mode and runs tool steps automatically, reducing confirmation prompts. Exiting plan mode still requires your confirmation.
- **Team Group Plan-stage**: Team groups use unified Plan-stage routing with auto-confirm when requirements are clear, failure recovery, mid-execution follow-ups, and a debug timeline showing plan execution stages.
- **DingTalk Integration**: DingTalk authentication now recovers automatically without interruption; attribution line updated to "send from my qoderwake".
- **Remote Session Context**: Remote Waker conversations now pass employee context correctly on page requests and follow-ups.
- **Homepage Memory Display**: Homepage memory section shows the most recent 50 entries without date filter limitation, and pending summary events refresh correctly.
### Bug Fixes
- Fixed some Windows users remaining on outdated versions after updates.
- Fixed task board swimlane view not showing all task types reliably when pagination is involved.
- Fixed background services not releasing system resources after sessions ended, which could affect performance.
### Task Board Officially Launched
### What's New
- **Task Board**: The Task Board is now officially launched — manage and track tasks across your Wakers from the sidebar navigation.
### Improvements
- **Automation History**: Trigger inputs now appear in conversation history for automation runs.
### Bug Fixes
- Pressing Enter during IME composition no longer triggers message send.
### DingTalk Meeting Notes MCP, Browser Relay MCP, Configuration Changes Without Interruption
### Improvements
- **Usage Panel Upgrade Prompt**: The upgrade entry at the bottom of the usage panel now displays persistently for individual users not on the highest tier, rather than only when quota is exhausted; a "View Details" link is added to the top-right corner
- **Mark All as Read**: Right-click menu on Waker and group chats supports clearing all unread badges in one click
- **DingTalk Meeting Notes MCP**: Query and read DingTalk meeting note summaries, transcriptions, and action items directly in Waker conversations (5 new tools)
- **Browser Extension Relay MCP**: With Browser Connector enabled, Waker can retrieve page content and perform browser actions through the browser extension
- **Configuration Changes Without Interruption**: Installing or modifying Skills, MCP, or Connectors no longer interrupts the current conversation; new configurations take effect automatically in the next turn
- **DingTalk Batch Mode Performance**: Faster message response when multiple DingTalk conversations are configured
- **DingTalk Missing Configuration Handling**: When DingTalk direct message configuration is incomplete, the service now stops explicitly with a prompt instead of silently skipping messages
### Bug Fixes
- Fixed Feishu channel replies losing message card content when the server closes the streaming connection early
- Fixed file picker opened from modals such as "Create from Public Project" not allowing click interaction with the directory list
### Model selector and interaction experience improvements
### Improvements
- **Model Selector**: Unavailable models are shown in a disabled state instead of hidden; disabled models are excluded from default/preferred model auto-selection.
- **Group Unread Badge**: Unread badge now includes historical unreads; background task sessions contribute to the corresponding Waker's unread count.
- **Subscription Plan**: Improved subscription plan information display.
- **Plan Mode**: Automatically approved when entering plan mode without manual confirmation.
- **Error Handling**: Improved error code display and page loading experience.
### Bug Fixes
- Fixed Linux file picker hanging for 120 seconds when no display session is available by falling back to the browser picker.
### Smarter automation inputs, unread badges, and group question forms
### Improvements
- **Smarter Automation Inputs**: Automations triggered via API now support template variables in the task prompt, so you can pass dynamic data from external services instead of writing fixed instructions every time.
- **Unread Badges**: Session history and task lists now show unread message counts, with separate badges for conversations and scheduled tasks so you can quickly spot what needs attention.
- **Group Question Forms**: Multi-question forms in Team Groups now display your completion progress and highlight any required questions you missed when you try to submit.
### Bug Fixes
- Fixed tool approval notifications not reaching you in IM channels, which could cause action results to go missing.
- Fixed sessions getting stuck on "thinking" and never returning a response.
- Fixed cancelled sessions not stopping promptly, which could leave stale sessions running in the background.
- Fixed Waker creation occasionally timing out before completing.
- Fixed the restart notification incorrectly reporting failure when background tasks were still finishing up.
- Fixed files from earlier conversations sometimes returning a "not found" error.
- Fixed newly created public projects not appearing in the Waker project list.
- Fixed Windows tray update handoff and terminal display issues on first launch.
### Reliability, cleaner responses, and group improvements
### Improvements
- **Group Loads Faster**: First-screen loading no longer fires redundant requests, and task states no longer bleed between sessions.
- **Unread Badge**: Displays 99+ for large counts; clicking the badge navigates directly to pending sessions for quick triage.
- **Chat Input Stays Editable**: The input box remains editable while a task is blocking, so you can prepare your next message.
- **Cleaner Model Responses**: Irrelevant DingTalk tool guidance no longer appears in regular conversations, and MCP tools activate correctly without cluttering context.
- **Update Reliability**: Daemon restarts reliably on macOS and Windows, and DingTalk dependencies auto-upgrade silently to keep IM and MCP tools available.
### Bug Fixes
- Fixed DingTalk group replies @mentioning the wrong person when multiple senders are active.
- Fixed sessions with an empty workspace path crashing on startup.
- Fixed macOS daemon not restarting promptly after a hot update.
- Fixed Windows pending updates not being applied during restart.
- Fixed incorrect version display in the Windows app shell.
- Fixed unstable unread navigation in Console groups.
### Thinking-indicator reliability fix
### Bug Fixes
- Fixed the "thinking" indicator getting stuck indefinitely when a completion event was missed.
### Unread Message Display, Artifacts Panel Toggle, Multi-Tab State Sync
### Improvements
- **Unread Message Display**: The Console chat list now shows unread message counts for Waker and group conversations; opening a conversation automatically marks it as read.
- **Artifacts Panel Toggle**: The conversation artifacts side panel can now be collapsed or expanded, giving more room to the chat area when closed.
- **Multi-Tab State Sync**: Worker running-state changes now sync in real time across multiple open Console browser tabs.
### Bug Fixes
- Fixed duplicate "thinking" status bars rendering simultaneously in a conversation.
- Fixed an issue where follow-up messages sent within 5 minutes via DingTalk were silently ignored.
- Fixed a 409 error when calling the restart API on Windows, which previously caused Waker restarts to fail.
- Fixed team group incorrectly marking the entire task as failed when certain non-essential members could not respond, and adjusted reply rules so these members no longer block task completion.
### Clearer resource package display
### Improvements
- **Resource Package Display**: Organization resource packages now show three clear states — available with a defined limit, available with unlimited usage, or unavailable — each with precise values and hover tooltips for guidance.
### Minor stability and display fixes
### Bug Fixes
- **Stability**: Fixed minor experience and display issues.
### More reliable session handling
### Improvements
- **Session Idle Timeout**: Sessions waiting for your response no longer expire from idle timeout — you can return later and pick up where you left off.
### Bug Fixes
- Fixed a rare issue where concurrent session operations could launch duplicate processes, causing unstable behavior.
### Model preference stability, DingTalk channel enhancements, and group plan reliability
### Improvements
- **Question Card Skip All**: Skip remaining unanswered questions at once, submitting defaults while preserving already-answered preferences.
- **Model Configuration Persistence**: Reasoning effort and context window settings are now retained across all model sources.
- **Waker Creation**: Bio/description field is no longer required when creating a new Waker.
- **Model Preference Stability**: Switching between history sessions no longer briefly flashes an incorrect model; previously selected models are properly remembered.
- **DingTalk Channel**: Support for AI card and ordinary card modes; model override per channel; configuration changes take effect immediately without manual restart.
- **Group Plan Execution**: Confirmed plans execute more faithfully with correct task assignments; question card submissions more reliable; input locked while questions are pending.
### Bug Fixes
- Fixed single-chat usage limit errors silently retrying instead of showing an immediate error message.
- Fixed model reasoning and context settings being lost in certain fallback scenarios.
### Model Configuration, Group Improvements, and Reliability Fixes
### Improvements
- **Model Runtime Configuration**: Model selector now supports viewing and configuring Reasoning Effort and Context Window, with a detailed model info panel.
- **Group Experience**: History loads on demand; execution artifacts and errors are displayed inline within the message stream.
- **Automation Task Reliability**: Scheduled tasks now include a self-recovery watchdog, and first-response latency for IM Channels is reduced.
### Bug Fixes
- Fixed certain usage limit errors causing silent retries instead of showing an immediate error message.
- Fixed importing configuration archives failing when file paths contain non-English characters.
- Fixed sessions being interrupted by a false "stuck" detection while the Waker is using tools.
- Fixed long-running conversations occasionally losing their connection after periods of inactivity.
### IM message localization, input drag-and-drop, and management polish
### Improvements
- **IM Message Localization**: System status and error messages in IM channels (queue waiting, approval blocks, media limits, processing failures, connection errors, etc.) now display in the user's configured language instead of fixed English text.
- **Input Field Drag-and-Drop**: Conversation and group chat input fields now support dragging images or files directly in. Images are uploaded as compressed thumbnails, non-image files are attached as file context references, and a guidance prompt is shown when the file path cannot be resolved.
- **Management Page Pagination**: The Waker Management page now paginates both the Waker list and the group list (12 per page).
### Bug Fixes
- Fixed an issue where custom-role Wakers without an avatar could display a blank placeholder; they now consistently show a default avatar.
### Cleaner file changes, and faster automation
### Improvements
- **Cleaner File Change Lists**: File change lists no longer show irrelevant system files (such as `.DS_Store`), and historical changes display more reliably.
- **Faster Automation Cleanup**: When a scheduled automation finishes, any leftover background processes are stopped immediately — no more waiting for a timeout.
### Windows release, clearer session errors, and Group polish
### What's New
- **Windows Release**: QoderWake for Windows is now officially available — download it from the official website.
### Improvements
- **Visible Session Errors**: When a session terminates due to an unexpected process exit, the console now shows the specific error instead of a generic disconnect notice.
- **Capped Group Auto-Summary**: Leader auto-summary replies in group conversations are now capped, reducing noise on the conversation timeline.
- **Readable Model Names in Selector**: The team model dropdown now shows readable model names when metadata is available, instead of raw model identifiers.
- **Subpath Deployment**: Apps deployed under a URL subpath now load all assets correctly without extra web server rewrite rules.
- **Action Suggestion Resilience**: When a group action suggestion responds too slowly, the system automatically skips it and continues processing the message — no more stalled conversations.
### Connector Stability & Group Polish
### Improvements
- **DWS Connector Probe**: Connectors load without auth popups and recover from Keychain errors or cache expiry.
- **Console Restart**: macOS users can restart and upgrade the daemon from Console even without LaunchAgent.
- **Leader Output**: Leader responses in group are more concise.
- **Feedback Log Collection**: Feedback ZIP is smaller and faster with a 40 MiB cap.
- **Multi-Filesystem Workspace**: Projects with multiple filesystem sources now resolve a unified workspace across all session types including group.
- **Historical Group Sessions**: Past group sessions now show their own historical state independently.
### Bug Fixes
- Fixed expired plan change confirmations blocking progress; they now become read-only.
- Fixed session list not correctly identifying which Waker owns each conversation.
- Fixed group sessions disconnecting permanently on credential expiry; they now reconnect seamlessly.
### Default Page and Session Auto-Recovery
### Improvements
- **Console Default Page**: Opening Console now lands on the Management page, providing an at-a-glance overview of all Wakers with an empty-state guide when no Waker exists.
- **Session Auto-Recovery After Daemon Restart**: Running sessions are automatically resumed after an unexpected daemon restart, so in-progress tasks continue without manual intervention.
### Waker Group release, DingTalk knowledge base integration, and IM mention preservation
### What's New
- **Waker Group**: Waker Group is now live — Wakers can collaborate as a team.
- **DingTalk Knowledge Base, Docs & Calendar**: The DingTalk MCP integration now supports knowledge base search and browsing, document listing/search/reading, calendar events, and meeting room management.
### Improvements
- **Manual Group ID for DingTalk Personal Mode**: You can now manually configure conversation ID or open conversation ID for DingTalk personal channels, with setup checks confirming whether the binding is in place.
- **IM Channel Message Localization**: System messages such as thinking placeholders and pairing prompts now follow your daemon language settings, supporting both Chinese and English.
- **Earlier DWS Authorization**: DingTalk message permissions are now granted during DWS setup instead of at runtime, making first-time replies and triggers faster and more reliable.
- **IM Mention Preservation**: Inbound IM messages now preserve @mention context for the model, with DingTalk mentions automatically resolving to user names via DWS when possible.
- **More Accurate Running Task Detection**: The system status API now distinguishes idle conversations from actually running tasks, so the update/restart prompt no longer mistakes idle sessions for active work.
### Bug Fixes
- Fixed DingTalk text callbacks stripping @mentions and leaving the model with broken sentences — mentions are now restored as readable text in the right places.
- Fixed leftover hidden self-evolution skill records from other accounts blocking the current account from rebuilding them.
- Fixed DWS login errors showing raw JSON in the console — now displayed as readable login prompts.
- Fixed the update/restart prompt counting idle conversations as running tasks.
### Smoother Project Creation and Project Source Setup
### Improvements
- **Project Source**: When adding a project source, selecting a valid local directory or entering a valid Git repository URL on the last row enables the Save button and submits that source, with no need to click "Add" first.
### Bug Fixes
- Fixed an issue where creating a new project in the working directory picker did not automatically select it with the correct working directory. The newly created project is now selected automatically so that tasks you send afterward run in the right working directory.
### Project context source editing fixes
### Bug Fixes
- Removing an extra blank context source draft row while creating a project no longer accidentally deletes context sources you have already added.
### Smoother update reminders
### Improvements
- **Update Reminder**: A dismissible reminder now appears in the bottom-right corner when a newer version has already been downloaded and is ready to install, letting you update now, close it, or be reminded later; once dismissed it stays hidden until an even newer version is ready.
### API trigger, launch at login, and a lighter idle footprint
### What's New
- **API Trigger**: You can now configure an API trigger for an automation and start a Waker on demand by sending a request to its endpoint, in addition to the existing automation triggers.
### Improvements
- **Launch at Login**: A new System setting starts the QoderWake background service automatically after you log in to your system. The macOS menu-bar "Launch at Login" toggle and the Console setting now reflect the same state.
- **Automatic MCP Connector Recovery**: Remote MCP connectors whose OAuth client has expired now reconnect automatically and transparently, with a "Re-auth" button as a fallback if recovery does not succeed.
- **Refined Usage Panel**: The usage overview now opens as a fixed overlay anchored to the app rail and refreshes each time you open it, and the global update/restart prompt no longer overlaps settings surfaces.
### Bug Fixes
- Fixed opening or refreshing an invalid or unavailable Console link, such as a missing session or resource, showing a blank or error page; it now redirects back to the conversation home.
- Fixed high CPU usage while the app is idle, noticeably lowering resource use when no tasks are running.
### Smarter restart prompts, fresher Waker home content, and more reliable Console navigation
### Improvements
- **Smarter Restart Prompt**: After an update, the restart prompt now warns about possible interruption only when a conversation is actually in progress, so idle sessions no longer trigger false alerts.
### Bug Fixes
- Fixed the "About Me" section on the Waker home page (core strengths, working style, delivery commitments) showing stale cached content after it was edited elsewhere.
- Fixed Console deep links such as session pages and the Waker home page failing with a blank screen or error when opened directly or refreshed.
### Global Settings, IM run file summaries, and steadier sessions
### What's New
- **Global Settings**: Added a dedicated Global Settings page in the settings menu, where you can set the AI's default reply language (independent of the interface language, applied to new sessions), enable "prevent system sleep while running," and access network diagnostics and app updates in one place, with light/dark theme support.
### Improvements
- **Run File Summary**: IM channel final replies now include a summary of the files changed in this run, shown as relative paths so you can confirm the delivery scope.
- **Update Restart Prompt**: After an update completes, the console now shows a unified restart prompt that tells you whether any session or automated task is still running before you restart, helping you decide when to restart.
- **Session Stability**: The console no longer stays stuck in a "thinking…" loading state forever after the underlying process ends unexpectedly, and new sessions can still be created reliably when occasional network or registration errors occur at startup.
### Bug Fixes
- Fixed an issue where IM channels such as DingTalk would sometimes return a subagent's intermediate content as the final reply; only the true final result is now returned.
### Skill marketplace self-evolution, memory growth timeline, and background memory
### What's New
- **Skill Marketplace & Self-Evolution**: Upload your own Skills and choose whether to allow self-evolution, both at upload time and from the detail page, with a clear "self-evolution" label. Marketplace Skills stay protected and read-only. When self-evolution produces a conflict, a prompt panel appears above the input box where you can ignore it or resolve it now, using a side-by-side AB diff with manual editing.
- **Memory Growth Timeline**: The Waker home page now shows a fishbone timeline of memory and Skill evolution. Each memory event is its own node, and clicking a node opens the memory version panel in place. Skill lifecycle governance milestones appear on the same timeline.
- **Background Memory During Idle Turns**: Between conversation turns, the Waker now distills core memory on its own, capturing user profile, project and account definitions, long-term goals, and constraints without an explicit memory action in the main conversation.
### Improvements
- **Skill Lineage View**: The lineage view now shows Project to Waker Skill contributions, with reference count and usage count displayed separately. The project-level Skill UI has been removed.
- **/wake Session Identity**: IM sessions started with `/wake` now carry the same sender identity and workspace context as regular IM sessions.
- **Larger IM File Support**: IM channels now accept files up to 100 MB, raised from 20 MB, across DingTalk, Feishu, WeCom Bot, and WeChat. Oversized files now return a clear message asking you to try a smaller file instead of failing silently.
### Bug Fixes
- Fixed an issue where the Waker list's "last conversation time" was incorrectly refreshed by trigger or automation runs; it now reflects real conversation activity.
- Fixed a false "startup failed" error reported for sessions while the process was actually running.
- Fixed ordered and unordered list markers not displaying correctly in console memory previews.
### IM new task command, conversation control enhancements, and stability fixes
### What's New
- **IM New Task Command**: Send `/wake` in any IM channel to start a new task — subsequent messages automatically flow into the new task without manual setup.
### Improvements
- **IM Sender Identity Awareness**: IM conversations now record sender identity, allowing the Waker to recognize which channel and user each message comes from.
- **IM Control Mode Restrictions**: New tasks in IM can only be created via dedicated commands — direct shell execution and file operations are blocked.
- **IM File Permission Tuning**: Permission checks now allow safe system temp directories and special device paths (e.g. `/dev/null`), reducing false blocks.
- **IM Session Interaction Limits**: IM sessions no longer trigger interactive prompts, avoiding unresolvable blocking in async messaging scenarios.
- **CLI Upgrade**: Qoder CLI upgraded to 1.0.14.
### Bug Fixes
- Fixed inconsistent error handling when an IM session is blocked — blocked sessions are now properly terminated, and the next message can start a new session automatically.
- Fixed IM replies being sent to the wrong context in certain scenarios.
- Fixed file/folder picker being triggered multiple times in succession, causing duplicate dialogs.
- Fixed disabled or removed MCP services being re-enabled by the sync mechanism.
- Fixed inaccurate status display after MCP authentication failure — now correctly marked as auth failed.
### IM channel workspace setup and session permission improvements
### Improvements
- **IM Channel Working Directory**: All IM channels (DingTalk Bot, DingTalk Personal, DingTalk AI Assistant, Feishu, WeChat, WeCom) now support setting a working directory — choose a local folder or bind an existing project. If not set, the default directory is used.
- **Project Picker in IM Settings**: The working directory selector shows both private and public projects, and lets you create a new project on the spot. Once selected, the available models refresh accordingly.
- **Seamless Directory Switching**: After changing an IM channel's working directory, existing sessions pick up the new directory on the next message — no need to recreate the channel.
- **Smarter Permission Checks**: IM session permissions now recognize the configured working directory, reducing unnecessary access blocks when directories change.
### Bug Fixes
- Fixed an issue in IM group chats where the final reply could incorrectly use the next sender's context when multiple users send messages in quick succession.
- Fixed DingTalk Personal channel authorization errors failing silently — the channel status now shows a re-authorization link for easy resolution.
- Added validation to prevent saving invalid working directory paths.
### DingTalk progress narration, model selector cleanup, and Ubuntu file picker fix
### What's New
- **DingTalk Progress Narration**: DingTalk user channels now support a "progress narration" mode, available in DingTalk user channel settings. When enabled, the digital worker sends real-time progress messages as it works, so you no longer have to wait for the final result.
### Improvements
- **Model Selector Cleanup**: The model dropdown now only shows user-facing model names. If your previously selected model goes offline, it switches to an available one automatically.
### Bug Fixes
- Fixed file/folder picker and image attachments not responding on Ubuntu Desktop.
- Fixed Waker name being unexpectedly cleared when opening the Edit Waker modal on Firefox.
### DingTalk channel improvements and a smoother setup experience
### Improvements
- **DingTalk Channel Edit Page**: IM channel settings now have a dedicated edit page, so updating an existing DingTalk channel is clearer and more straightforward.
- **Simpler DingTalk Plugin Setup**: The console now pulls DingTalk plugin configuration automatically, cutting down the manual steps when setting up DingTalk.
- **Safer macOS Upgrades**: When upgrading the macOS DMG runtime, the CLI now asks before overwriting an existing install, so you won't lose data by accident.
- **Faster Lightweight SDK Startup**: Lightweight SDK spawns now skip MCP server connections they don't need, so quick SDK operations start up faster.
- **More Accurate IM Session Permissions**: Plugin workspace directories are now resolved at runtime, making permission checks more reliable across different deployment setups.
- **Quota Exhaustion Guidance**: When you run out of credits, the prompt now links straight to the renewal or upgrade page — no more hunting around.
### Bug Fixes
- Fixed the Linux release binary failing to start on older distributions by realigning the glibc version.
- Fixed the CLI not properly guarding cross-Waker changes and mutation resource links, which could lead to unintended side effects.
### IM Channel Security Enhanced, DingTalk User Matching, Memory & Skill Self-Evolution
### Improvements
- **IM Channel Security Enhanced**: IM sessions now enforce permission boundaries, ensuring conversations and commands stay within allowed workspaces for safer Agent operations.
- **DingTalk Channel User Matching**: The DingTalk channel now supports nickname-based identity resolution and message filtering for more accurate user matching.
- **Memory & Skill Self-Evolution**: Multiple improvements to the memory and Skill self-evolution pipeline for greater stability and efficiency.
### IM channel expansion, scheduled automation, and stronger session reliability
### What's New
- **More IM Channels**: Wakers can now connect through Feishu, WeChat, and WeCom Bot, in addition to the existing DingTalk channels.
- **Skill Marketplace Search**: The CLI and console now support searching and filtering Skill Marketplace entries more easily.
### Improvements
- **IM Channel Experience**: IM replies now handle streaming, media, pairing/open-access policies, and rapid consecutive messages more reliably.
- **Session Recovery**: Console sessions recover better from SSE reconnects, daemon restarts, gateway fallback, and idle/restart windows.
- **Memory System**: Project memory now supports custom sections, improved locale initialization, and more accurate usage-state attribution.
### Issue Fixes
- Fixed IM channel replies being lost when the same sender sends multiple messages quickly.
- Fixed worker/model errors being silently dropped in IM channels; users now receive clearer failure messages.
- Fixed SSE reconnect scenarios that could leave the console stuck in a thinking or pending state.
- Fixed duplicate output rendering after reconnect or event replay.
- Fixed stop-button behavior when a session requires restart.
- Fixed quota-exceeded errors so they render as friendly user-facing cards.
- Fixed oversized image reads that could trigger BAD\_REQUEST failures when many images are attached.
- Fixed Skill reference completion to use the correct Skill display name.
- Fixed other known issues.
### Multiple Wakers can now collaborate within the same project; Memory & Skills upgrades
### What's New
- **Public Projects**: You can now create "public projects," letting all Wakers under a single account share the context and artifacts within a project.
- **GitHub Triggers**: Triggers now fire correctly even for repositories where the current account is not a collaborator.
### Improvements
- **Skill Management**: Streamlined the workflow, with the accompanying Skill templates polished to match.
- **Memory Self-Evolution**: Memory now evolves automatically based on usage, and templates adapt to the system language.
### Bug Fixes
- After logging out and signing back in with the same account, digital employees no longer show up empty in the console or in qoderwake waker list.
- On macOS, a failed "launch at startup" registration no longer blocks the rest of the installation.
- Fixed a scenario where GitHub event triggers were previously failing.
- Fixed other known issues.
### 0.0.10
### QoderWake is now open for public beta.
QoderWake is an AI digital worker runtime platform that lets you build a team of "digital workers" (Wakers) on your local machine. Each worker has a role, a name, a persona, and specialized skills — ready to chat or get work done whenever you need them.
This public beta supports macOS (13+) and mainstream Linux distributions. Windows support is not yet available.
### AI Employee
- Create multiple workers, each with independent identity, memory, skills, and workspace
- Built-in role templates (Software Engineer, QA, Product Manager, Data Analyst, Content Operations, etc.), with full support for custom roles
- Assign tasks through natural language conversation, with real-time visibility into thinking process, code output, and tool invocations
- Workers proactively ask for approval before performing sensitive operations, with three-tier permission policies (Allow / Ask / Deny)
### Automated Triggers
- Multiple trigger types including scheduled, GitHub Webhook, and more
- Run history, calendar view, monthly statistics, and execution limits
- "Test pull" before saving — read-only validation of data source connectivity
### Skills & Tool Integration
- Built-in skills ready out of the box, one-click install from the skill marketplace, custom skill uploads, and automatic skill distillation
- MCP protocol support for connecting external tools, with full OAuth 2.0 authorization flow
- Fine-grained on/off control at the individual tool level
### Long-term Memory
- Persistent memory across sessions, organized by sections (user preferences, project knowledge, key decisions, etc.)
- Personal memory (per worker) and project-level shared memory
- Built-in semantic search, daily auto-consolidation, version snapshots and rollback
### Multi-channel Access
- **Web Console**: Local visual management interface covering all operations, with dark theme and language switching
- **IM Channels**: Connect workers to IM platforms (e.g. DingTalk) for direct interaction in group chats or private messages
- **CLI**: Full-featured command-line tool including process management, diagnostics, and backup/restore
# Credits
## **What are Qoder Credits?**
Users don't have unlimited access to premium large language models. Instead, there's a quota system based on credits. Credits represent the resource quota consumed by AI when performing tasks. In Qoder, the following user requests will consume Credits:
- Editor
- Inline Chat
- Ask Mode
- Agent Mode
- Quest
- Agent Mode
- Experts Mode
- Knowledge
- Repo Wiki
- Knowledge Card
Keep in mind that the number of Credits used can vary depending on the complexity of the task and the specific premium model involved. For a detailed breakdown of how Credits are consumed for different tasks, check out our [Task and Credits Consumption Guide](https://docs.qoder.com/Credits#task-and-credits-consumption-guide).
## **How to deduct the Credits?**
Credits acquired at different times have varying expiration dates. Our system automatically uses the credits that are set to expire first, ensuring you maximize the value of your credits.
Even when a user has used up their quota for premium models, i.e. their credits have been depleted, we still provide a limited daily allowance of basic model calls. This ensures that our users can continue to use our product's core features without interruption.
## **Error**
Failed Qoder model requests do not result in Credits deductions. Credits are only consumed when a model API call is successful.
## **Task and Credits Consumption Guide**
Different tasks require different models, each with its own associated costs. To address this, we've analyzed the resource consumption of our users' online activities. Based on this data, we've established a correlation between the usage of various models and credits consumption. This approach helps our users better understand how we calculate and deduct credits for different operations.
> For example, a single Ask Mode request in Editor might use a premium large language model, consuming a certain number of Input and Output Tokens. The credits deducted are calculated based on the model used and the total token consumption for both input and output. When a User sends an Agent Mode request in Editor, it often involves multiple premium model calls behind the scenes, using significantly more resources than a simple Ask request. Quest Experts Mode coordinates multiple agents in parallel and typically uses even more resources. For Knowledge, Repo Wiki resource consumption is measured based on the model inference required to generate a knowledge base for a specific code repository.
The values shown in the table are just estimates based on our statistical analysis. Actual credits deductions may vary and will be based on real-time usage. We're also working on optimizations to ensure we can get the same work done while using fewer resources.
| | Median (50K context window) | Median (200K context window) |
| :-------------------- | :-------------------------- | :--------------------------- |
| Editor - Ask Mode | \~ 3 Credits / User Request | \~ 4 Credits / User Request |
| Editor - Agent Mode | \~ 7 Credits / User Request | \~ 12 Credits / User Request |
| Quest - Agent Mode | / | \~ 50 Credits / User Request |
| Quest - Experts Mode | / | \~ 75 Credits / User Request |
| Knowledge - Repo Wiki | / | \~ 50 Credits / Repository |
**Note:** In the future, as we roll out new features, we may update our credits consumption rates based on the resources these features require. This means the number of credits deducted for certain actions might change to reflect the actual resource usage of new functionalities.
## **Checking Your Credits Usage**
### View Usage in IDE
You can find the Credits usage button in the bottom-right corner of the IDE. Click it to view a usage preview and shared add-on credits status.
### View Usage on Website
Log in to the Qoder website. Click on your avatar in the top-right corner. Navigate to Settings > Usage.
Here, you'll find your current Plan and a breakdown of available and used Credits:
- **Plan Credits**: Credits included in your subscription plan, valid for the current billing period. They reset to zero when the period ends.
- **Add-on Credits**: Acquired through purchases or promotional events, for personal use only. See [Credit Packs](https://docs.qoder.com/account/pricing#credit-pack) for details.
- **Usage Priority**: The system always consumes Credits expiring soonest first. When expiration dates are the same, Plan Credits are used before Add-on Credits.
- **Expiration**: Different types of Credits have their own expiration dates. You can view the projected expiration in the Credits log. (Note that actual expiration may occur earlier due to factors like account upgrades. See the Credits log section below for details.)
**Get More Credits**: Once your Credits run out, you can still use basic models, subject to their own usage limits. You can [upgrade your plan](https://qoder.com/pricing) or [purchase a Credit Pack](https://docs.qoder.com/account/pricing#credit-pack) at any time.
**Get More Credits**: Once your Credits run out, you can still use basic models, subject to their own usage limits. You can [purchase a Credit Pack](https://docs.qoder.com/account/pricing#credit-pack) at any time.
## **Credits Log: Credits History and Tracking**
The credits acquisition history provides a comprehensive record of all credits received, including the reason for acquisition, the amount, and the effective and expiration dates. This allows you to easily track your credit sources.
Common acquisition types:
| Description | Details |
| :-------------- | :----------------------------------- |
| Plan Credits | Credits included in your plan |
| Credit Purchase | Purchased via Credit Packs |
| Bonus Credits | Granted through events or promotions |
Important Note on Expiration Dates: \
Please be aware that the expiration dates shown in the credits log are based on the initial projection at the time of issuance. Actual expiration dates may change due to account upgrades or other factors. To determine the true expiration date, you'll need to consider your Plan change history.
Remember, the credits log only shows the history of credits acquisitions. To check your current available credits usage, please refer to the 'Credits Usage' card in your account dashboard.
# Pricing
For individual users, Qoder offers Free, Pro, Pro+ and Ultra plans. For organization purchases, compare the [Teams and Enterprise plans](/account/enterprise/pricing). Choose the plan that best matches your needs.
## **Individual Plans**
The contents of each plan are as follows, and the paid plan is used as a natural monthly subscription. [Credits](https://docs.qoder.com/Credits) are used as the resource usage unit of Qoder.
| Plan | **Free** | **Pro** | **Pro+** | Ultra |
| :-------------- | :---------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| Price | Free | 20 USD/mo | 60 USD/mo | 200 USD/mo |
| Functionalities | - 2-week Pro trial - Limited completions and next edits (NES) - Bring Your Own Key (BYOK) | - More completions and next edits (NES) - Limited Credits for chat and agent requests - Quest - Repo Wiki - Knowledge Card | - More completions and next edits (NES) - Limited Credits for chat and agent requests - Quest - Repo Wiki - Knowledge Card | - More completions and next edits (NES) - Limited Credits for chat and agent requests - Quest - Repo Wiki - Knowledge Card |
| Quota | - Basic models for limited user messages. | - 2,000 Credits / month for premium models - Once run out of credits, Qoder will switch to basic models, which have limited user messages. | - 6,000 Credits / month for premium models - Once run out of credits, Qoder will switch to basic models, which have limited user messages. | - 20,000 Credits / month for premium models - Once run out of credits, Qoder will switch to basic models, which have limited user messages. |
**NOTE**: Your Pro, Pro+ and Ultra plan quota covers premium model resources equivalent in value to your subscription fee (\$20 for Pro, \$60 for Pro+ and \$200 for Ultra) , plus any extra resource bonuses we provide. Credits in your plan are valid for the duration of your current subscription period. These credits will automatically reset to zero when your subscription period ends.
The 2-week Pro Trial includes
- 300 credits
- Unlimited Completions & Next Edits
- Chat Ask & Agent
- Experts Mode
- Quest
- Repo Wiki
- Knowledge Card
## Which plan should I choose?
The Pro Plan is ideal for your day-to-day development if you primarily use code completion and light Agent assistance.
If you are a heavy user of the Agent for autonomous coding, the Pro+ Plan is designed to better meet your more demanding needs.
The Ultra plan is recommended for users who frequently run long-running tasks, such as Quest.
## **Checking Your Credits Usage**
You can view your credits usage for the current subscription period at any time through the Usage page in your personal settings. Different features consume credits at varying rates. See the [Credits](https://docs.qoder.com/Credits) section for details.
## **What Happens When You Run Out of Credits?**
When you're running low on credits, you'll see clear notifications on your personal usage page and in Qoder. If you completely run out of credits quota, you'll automatically switch to the basic models service, which will continue to serve you. Basic models have a daily limit; if you reach this limit, you'll need to wait until the next day to continue using the service.
Here's how to get more Credits:
- [Upgrade to a higher plan](https://qoder.com/pricing) for a larger Credits allowance
- [Purchase a Credit Pack](#credit-pack) for on-demand top-ups
- [Purchase a Credit Pack](#credit-pack) for on-demand top-ups
## **Credit Packs**
Pro, Pro+, and Ultra subscribers can purchase Credit Packs at any time to top up their Credits. When your plan allowance isn't enough, a Credit Pack is the quickest way to keep going.
### Pricing & Specs
| Item | Details |
| :------------ | :---------------------------------------------------- |
| Payment model | Prepaid, one-time purchase, stackable |
| Price | \$20 USD / 1,500 Credits |
| Increment | 1,500 Credits |
| Validity | **1 month** from purchase date, unused Credits expire |
| Refunds | **Not refundable** |
You can hold multiple Credit Packs at the same time — each one has its own independent expiration.
### How to Purchase
1. Log in to [Qoder](https://qoder.com/account/usage) and go to **Settings > Usage**.
2. Click the purchase button in the **Get More Credits** card.
3. Choose the number of Credits you need (in increments of 1,500).
4. Review the order (including any discount details) and complete payment.
### Viewing Your Credit Packs
After purchase, check the **Add-on Credits** card on the **Usage** page to see your active Credit Packs. A "**Credit Purchase**" entry will also appear in your Credits log.
### Usage Priority
When you have Credits from multiple sources (Plan Credits and Add-on Credits), the system always consumes the ones expiring soonest first.
## **Pro Trial Rules**
We're happy to offer new users a free 14-day Pro trial upon their first sign-in to Qoder Client (**requires latest version; not available on virtual machines**), along with 300 credits to explore our Pro Plan features. To ensure a fair and quick experience for everyone, we've set reasonable usage limits. This offer is limited to one account per user; any additional trial accounts created will be frozen.
## **Upgrading Your Subscription Plan**
You can upgrade your subscription plan at any time. Any unused credits from your current plan will automatically carry over and won't be lost. Please note that once your credits carry over, this action cannot be reversed.
- Upgrading from Pro Trial: If you upgrade during the trial period, any unused gifted credits will automatically transfer to your account as an add-on pack, maintaining their original expiration date.
- Upgrading from Pro to Pro+: If you upgrade from Pro to Pro+ mid-subscription, unused credits from your Pro Plan will automatically transfer to your account as an add-on pack, keeping their original expiration date. Your original Pro Plan will immediately become inactive, and your new Pro+ Plan subscription period will begin.
Upgrading never wastes your existing Credits — go ahead with confidence.
## **Downgrading Your Subscription Plan**
Subscription cancellation is available at any time. Your current plan remains fully active through the end of your billing period, after which your account automatically reverts to the Free. Please note that any unused credits will expire upon downgrade and cannot be transferred.
We don't support immediate plan downgrades within a subscription period.
## **Advanced Features**
In contrast to the Free, paid plans offer the following advanced features:
- Quest: An AI-assisted programming feature designed for task delegation, long-running development tasks. For more information, see [Quest](https://docs.qoder.com/user-guide/quest/overview).
- Repo Wiki: Automatically generates structured documentation for your project while continuously tracking code and documentation changes. For more information, see [Repo Wiki](https://docs.qoder.com/user-guide/repo-wiki).
- Experts Mode: Uses multiple agents to break down and complete complex development tasks in parallel, covering planning, implementation, testing, and quality review. For more information, see [Experts Mode](/user-guide/quest/experts-mode).
## **For Organizations**
For centralized purchasing and governance, compare the capabilities, seat pricing, and Credits rules of the [Teams and Enterprise plans](/account/enterprise/pricing).
For billing-related questions, please refer to the [Billing](https://docs.qoder.com/account/Billing) section.
# Billing
> This article covers billing for Qoder and shows you how to view and manage your subscription and invoices.
This article covers billing for Qoder **personal plans**. For organization billing and pricing, see [Teams and Enterprise plans](/account/enterprise/pricing).
## Manage Your Plan
Sign in to the [Qoder website](https://qoder.com/account/plan), click your avatar in the top-right corner, and go to **Settings > Plan & Billing**.
Here, you can view your current subscription plan and easily upgrade to a higher tier.
## Orders & Invoices
In the **Invoices** section, you can view your entire payment history and download any of your past invoices for your records.
### Items & Order Types
| Item | Description |
| :---------- | :------------------- |
| Pro Plan | Pro subscription |
| Pro+ Plan | Pro+ subscription |
| Ultra Plan | Ultra subscription |
| Credit Pack | Personal Credit Pack |
| Order Type | Description |
| :--------- | :----------- |
| Purchase | New purchase |
| Renewal | Renewal |
You can filter the order list by Item and Order Type to quickly find the record you need.
### Order Status
| Status | Description |
| :-------- | :----------------------------- |
| Unpaid | Order created, pending payment |
| Paid | Payment completed successfully |
| Cancelled | Order has been cancelled |
### Invoice Details
Each order includes detailed item information such as the product name, quantity, discount details, and tax. For paid orders, the payment method is also recorded.
## Billing Cycle
Our subscriptions operate on a monthly billing cycle.
Your plan will automatically renew each month on the same date you originally subscribed. The renewal payment is processed one day before your current cycle expires. If the renewal payment fails, your subscription for the next cycle will be canceled, your account will be downgraded to the Free, and any unused Credits will be forfeited.
**Billing Cycle Examples:**
- **Standard Subscription:** If you subscribe on August 16, 2025, your current billing cycle will end at 23:59:59 on September 16, 2025.
- **End-of-Month Subscription:** If you subscribe on February 28, 2025, your cycle ends at 23:59:59 on March 28, 2025. If you subscribe on March 31, 2025, your cycle ends at 23:59:59 on April 30, 2025 (as April does not have 31 days).
Credit Packs are one-time prepaid purchases and are not subject to auto-renewal. Each pack is valid for 1 month from the date of purchase; any unused Credits expire automatically.
## Accepted Payment Methods
Qoder currently supports the following payment methods:
- **Cards**: Visa, Mastercard, UnionPay, American Express, Discover, Diners Club, and JCB
- **Alipay**
- **Digital wallets**: Google Pay and Apple Pay
## Canceling Your Subscription
On the **Plan & Billing** page, find the **Plan** card and click **Manage > Cancel Subscription**.
Please note that the cancellation will take effect at the end of your current billing cycle. This means your subscription will not automatically renew. Your current subscription will remain active until its expiration date.
### **Billing FAQ**
**Why did my payment fail?**
A payment can fail for several reasons, including:
- **Insufficient funds:** Your account does not have enough money to cover the charge.
- **Expired or invalid card:** The card you used for the payment has expired, or the details were entered incorrectly.
- **Bank decline:** Your bank has rejected the payment request. Please contact your bank for more information.
**How do I update my billing information?**
You can update your billing address and manage payment methods on the **Settings > Plan & Billing > Manage Billing Information** page. **Your default payment method will be automatically charged for subscription renewals.** This change will apply to all future purchases and renewals.
We use Antom for secure payment processing. Please note that changes only affect future transactions; we are unable to modify information on past invoices.
**When does my plan renew and my limits reset?**
Your Individual plan will automatically renew on the last day of each billing cycle. The renewed plan becomes active on the following day, which marks the start of your new subscription period. At that time, your usage quotas will be refreshed according to your active plan.
**How can I request a refund?**
**Subscription refunds**: You are eligible for a refund if you request it within 24 hours of subscribing and have not used any Credits. To apply, please send your Qoder account and bills to [refund@qoder.com](mailto:refund@qoder.com). Qoder's support team will assist you with your issue as soon as possible. Refunds will take 5-10 days.
**Credit Pack refunds**: Credit Packs are **not refundable**. Please confirm your needs before purchasing.
**I have other billing questions. How can I get help?**
If you have a billing question that isn't answered here, please email us at [**contact@qoder.com**](mailto:contact@qoder.com).
For faster support, please write to us from the email address associated with your account and provide a detailed description of your issue.
# Qoder 1st Anniversary × Qwen3.8-Max Official Launch: Claim 800–2,000 Model Calls
On August 3, Qwen3.8-Max is officially launched on Qoder, with first-class support across all platforms.
Qwen3.8-Max is the latest generation of the Qwen foundation model series, with 2.4 trillion parameters. Compared to the previous flagship Qwen3.7-Max, it delivers comprehensive improvements in core capabilities such as code engineering, professional office work, and deep reasoning.
August also marks Qoder's first anniversary. Since its launch last August, Qoder has served over 5 million users worldwide.
To celebrate Qoder's first anniversary and the launch of this new model, we are offering two promotions:
- **Qwen3.8-Max Limited-Time Free Calls**: New registered users and existing paid users can claim **800 free calls** to Qwen3.8-Max; placing an order during the event can stack an additional **2,000 calls**.
- **Off-Peak Discount**: Qwen3.8-Max at **full price during the day, 50% off during off-peak hours** — enjoy the new model at a discount during off-peak hours.
## Qwen3.8-Max Limited-Time Free Calls
### Benefits Overview
| **Eligible Users** | **Free Calls** | **How to Claim** |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------- |
| New registered users (registered as Pro Trial) | **800 calls** | Claim in-app, limited to 1 claim during the event |
| paid users (registered before August 3, with a paid order placed between July 3 00:00 and August 2 23:59) | **800 calls** | Claim in-app, limited to 1 claim per user |
| New subscribers during the event (Pro, Pro+, Ultra, Personal Resource Pack) | **2,000 calls** (stackable with the 800 calls) | Claim in-app after placing an order, limited to 1 claim per user |
800 calls can run approximately 80 tasks, and 2,000 calls can run approximately 200 tasks (based on averages; actual experience may vary depending on task size).
### Event Details
- **Start time**: August 3, 2026, 10:00 (UTC+8)
- **End time**: September 3, 2026, 23:59 (UTC+8); claims must be made before this deadline
- **Claim entry**: Available on Qoder IDE / Qoder JetBrains Plugin / Qoder CLI / QoderWake
- **Applicable products**: Qoder IDE / Qoder JetBrains Plugin / Qoder CLI / QoderWake / Qoder Cloud Agents / Qoder Mobile/Web App — claim on one platform, use across all
- **Eligible users**: Individual plan users only
- **Applicable tier**: Qwen3.8-Max model
- **Promotion details**: New registered users and paid subscribers before the event each receive **800 free calls**; placing an order during the event (Pro, Pro+, Ultra, Personal Resource Pack) grants an additional **2,000 calls**, stackable
- **Activation**: The 800 calls for new and existing paid users must be claimed in the "Usage" panel in-app; the 2,000 calls from orders must also be claimed in the "Usage" panel
- **Consumption rules**: When using Qwen3.8-Max, event free calls are deducted first; once exhausted, normal billing applies using plan Credits / Resource Pack
### How to Use
1. Update Qoder to the latest version (Qoder IDE / Qoder JetBrains Plugin / Qoder CLI / QoderWake).
2. Log in to your account and claim in the "Usage" panel in-app (order bonus calls must also be claimed manually).
3. Switch to Qwen3.8-Max in the model tier selector and start using.
### Other Terms
- **Non-transferable**: Event benefits are non-transferable and cannot be exchanged for cash.
- **Cancellation & revocation**: If a user violates obligations, terms, policies, laws, or rules related to their account or any Qoder service or product, Qoder reserves the right to immediately cancel, void, and revoke issued benefits.
- **Event period**: This limited-time promotion has a defined start and end time. Qoder reserves the right to terminate or modify this event and its terms at any time.
- **Event changes**: Qoder reserves the right to change the terms, benefit structure, or eligibility conditions of this promotion at any time. Any changes will be communicated by updating this document or through other notifications.
**Contact us**: If you have any questions, please reach out to [contact@qoder.com](mailto:contact@qoder.com).
### FAQ
**Q: Who can claim free calls?**
New users who register during the event (as Pro Trial at the time of claim), and users who registered before the event and had a paid subscription between July 3 00:00 and August 2 23:59, can claim 800 calls in-app; users who place an order during the event (including Pro, Pro+, Ultra, Personal Resource Pack) will receive an additional 2,000 calls. Qoder reserves the right to disqualify accounts with abnormal registration or usage behavior, and retains final interpretation rights for this event.
**Q: What is the relationship between the 800 calls and 2,000 calls?**
The 800 calls for new or existing paid users must be claimed in-app; the 2,000 calls are issued after placing an order during the event. Both can be used together.
**Q: When do the free calls expire?**
All unused calls expire on September 30, 2026, 23:59 (UTC+8). We recommend claiming and using them early.
**Q: Which are deducted first — free calls or plan Credits?**
When using Qwen3.8-Max, event free calls are deducted first; once exhausted, normal billing resumes using plan Credits.
**Q: Are Teams plan users eligible?**
This anniversary benefit is only for individual plan users. Teams plans are not included at this time.
**Q: What if I can't find the claim entry?**
Please update your client to the latest version and confirm you are logged in. If your account meets the criteria but you still don't see the entry, please contact official support.
## Off-Peak Discount: Full Price During the Day, 50% Off During Off-Peak Hours
To help developers make the most of low-traffic hours, Qwen3.8-Max offers time-based Credits multiplier discounts: during off-peak hours (daily 22:00 to 08:00 the next day, UTC+8), enjoy a 50% discount; regular hours are at full price, ensuring all-day access. Pro Trial and paid users are automatically enrolled — no sign-up required.
### Discount Overview
Times are based on Singapore Time (SGT, UTC+8), including weekends and public holidays. Using models other than those listed above is billed at standard rates. Discounts only affect Credits pricing; model quality is unaffected.
| **Model** | **Standard Multiplier** | **Regular Hours (08:00–22:00)** | **Off-Peak Hours (22:00–08:00)** |
| ----------- | ----------------------- | ------------------------------- | -------------------------------- |
| Qwen3.8-Max | 0.5x | 0.5x (full price) | 0.25x (50% off) |
### Event Details
- **Start time**: August 3, 2026 (UTC+8)
- **End time**: To be determined. We will notify in advance through Qoder's official website, email, X, and other official channels. We recommend starting to use it early.
- **Applicable products**: International site Qoder IDE / Qoder JetBrains Plugin / Qoder CLI / QoderWake / Qoder Cloud Agents / Qoder Mobile/Web App
- **Eligible users**: Individual plan Pro / Pro+ / Ultra / Trial (during Pro Trial period); Teams plan also included
- **Applicable tier**: Qwen3.8-Max model
- **Activation**: Simply update to the latest version — automatically effective, no claiming or settings changes required
### How to Use
1. Update Qoder to the latest version.
2. Switch to Qwen3.8-Max in the model tier selector.
3. Make requests during off-peak hours (22:00–08:00, UTC+8) and the 50% discount will be applied automatically.
### Global Time Zone Reference
Off-peak hours are based on Singapore Time (SGT, UTC+8). Below are the corresponding local times for major time zones. Times below are based on 2026 Northern Hemisphere daylight saving time; during standard time, some regions may shift by 1 hour. Please refer to the UTC window (14:00–00:00 UTC) for accuracy.
| **Time Zone** | **Off-Peak Hours (Local)** | **Regular Hours (Local)** | **Off-Peak Coverage** |
| :-------------------------------------- | :------------------------- | :------------------------ | :------------------------- |
| US Pacific PDT (UTC-7) | 07:00–17:00 | 17:00–07:00 | Weekday daytime |
| US Eastern EDT (UTC-4) | 10:00–20:00 | 20:00–10:00 | Weekday daytime to evening |
| UK BST (UTC+1) | 15:00–01:00 (+1) | 01:00–15:00 | Afternoon to early morning |
| Central Europe CEST (UTC+2) | 16:00–02:00 (+1) | 02:00–16:00 | Afternoon to late night |
| India IST (UTC+5:30) | 19:30–05:30 (+1) | 05:30–19:30 | Evening to early morning |
| Singapore / Hong Kong / Beijing (UTC+8) | 22:00–08:00 | 08:00–22:00 | Evening to next morning |
| Japan / Korea JST (UTC+9) | 23:00–09:00 | 09:00–23:00 | Late night to morning |
| Australia Eastern AEST (UTC+10) | 00:00–10:00 | 10:00–00:00 | Early morning to morning |
### Other Terms
- **Non-transferable**: Discounts are non-transferable and cannot be exchanged for cash.
- **Credits count toward quota**: Credits consumed during discount hours count toward your monthly plan quota — they are not extra free credits.
- **Cancellation/forfeiture**: If a user violates obligations, terms, policies, or regulations related to their account or Qoder services, Qoder reserves the right to immediately cancel, forfeit, and/or revoke all issued benefits.
- **Event changes**: Qoder reserves the right to terminate or modify this event and its terms at any time. Changes will be notified by updating this document or through other means.
**Contact us**: If you have any questions, please reach out to [contact@qoder.com](mailto:contact@qoder.com).
### FAQ
**Q: When does the off-peak discount take effect?**
Daily from 22:00 to 08:00 the next day (UTC+8), including weekends and public holidays.
**Q: Is there a discount during regular hours?**
Regular hours (08:00–22:00 UTC+8) are billed at full price (0.5x); off-peak hours enjoy a 50% discount (0.25x).
**Q: Can I still enjoy the discount after Credits are exhausted?**
No. Once Credits are exhausted, you need to upgrade your plan, purchase a resource pack, or wait for the next billing cycle.
**Q: Does model quality change during discount hours?**
No. The model is the same — reasoning capabilities and context length remain consistent. The discount only affects Credits pricing.
**Q: Do Credits consumed during discount hours count toward monthly quota?**
Yes. The discount reduces the Credits multiplier, not as extra free credits. Consumption still counts toward your monthly plan quota.
**Q: Can free trial users participate?**
New users who first log in to Qoder receive a 14-day Pro Trial (with 300 Credits), and the discount is automatically applied during the Pro Trial period. Trial users not within the Pro Trial period or with exhausted Credits are not eligible.
# Cantus Model — Limited-Time Discount
Cantus is Qoder's built-in top-tier intelligent model, excelling at extended autonomous task execution. To celebrate the launch of Cantus, it is now available at a limited-time discount.
## Campaign Details
- **Start date**: July 19, 2026
- **End date**: July 31, 2026, 23:59
- **Products**: Qoder IDE / Qoder JetBrains Plugin / Qoder CLI / QoderWake / Qoder Cloud Agents / Qoder Mobile/Web App
- **Eligible users**: All Qoder users
- **Model**: Cantus
- **Benefit**:
- Individual plans: including Free, Pro, Pro+, and Ultra — Cantus at 50% off (billing coefficient reduced from 3.2x to 1.6x)
- Enterprise plans: including Teams and Enterprise — Cantus at 20% off (billing coefficient reduced from 3.2x to 2.56x)
- **Activation**: Automatic. No action needed — no code, opt-in, or signup required.
## How to Use
1. Update Qoder to the latest version
2. Switch to "Cantus" in the model tier selector
## Other Terms
- **Non-transferable**: Campaign benefits are non-transferable and cannot be redeemed for cash.
- **Cancellation/Forfeiture**: If a user violates any obligations, terms, policies, laws, or rules associated with their account or any Qoder service or product, Qoder reserves the right to immediately cancel, forfeit, and reclaim all issued benefits.
- **Campaign period**: This limited-time offer has a defined timeframe. Qoder reserves the right to terminate or modify this campaign or its terms at any time.
- **Changes**: Qoder reserves the right to change the terms, benefit structure, or eligibility criteria of this limited-time offer at any time. Any changes will be communicated by updating this document or through other means.
**Contact us**: If you have any questions, please reach out to [contact@qoder.com](mailto:contact@qoder.com).
## FAQ
**Q: Are other model tiers also discounted?**
No. This campaign applies exclusively to the Cantus model.
**Q: Are Add-on Credits also discounted?**
Yes. During the campaign, Add-on Credits used with Cantus are also billed at the discounted rate.
# Qwen3.8-Max-Preview All-Day 90 Percent Off, Off-Peak Up to 98 Percent Off
Qwen3.8-Max-Preview is the latest foundation model in the Qwen family, with 2.4T parameters.
Compared to the previous flagship Qwen3.7-Max, the new model delivers significant improvements in coding and professional productivity (Cowork), demonstrating world-leading comprehensive capability in complex long-horizon tasks such as full-stack development, data analysis, and Office workflows — and it's still evolving.
To celebrate the launch, we're offering two benefits:
- **Limited-time benefit**: Qwen3.8-Max-Preview model calls at 90% off Credits consumption — effectively 10x the usage;
- **Off-peak discount benefit**: Qwen3.8-Max-Preview enjoys off-peak discount starting at 98% off
## Limited-Time Benefit: 10x Usage
### Campaign Details
- **Start date**: July 19, 2026
- **End date**: August 3, 2026 at 10:00 (UTC+8)
- **Products**: Qoder IDE / Qoder JetBrains Plugin / Qoder CLI / QoderWake / Qoder Cloud Agents / Qoder Mobile/Web App
- **Eligible users**: Pro / Pro+ / Ultra / Pro Trial, as well as Teams and Enterprise users.
- **Model tier**: Qwen3.8-Max-Preview
- **Benefit**: Qwen3.8-Max-Preview at 90% off (billing coefficient reduced from 0.5x to 0.05x)
- **Activation**: Automatic after updating to the latest version — no action needed
- **Note**: The Experts mode in Qoder IDE and certain sub-Agent calls to specific models during tasks are not covered by this campaign — Credits usage details will reflect this accurately.
### How to Use
1. Update Qoder to the latest version
2. Switch to Qwen3.8-Max-Preview in the model tier selector
### Other Terms
- **Non-transferable**: Campaign benefits are non-transferable and cannot be redeemed for cash.
- **Cancellation/Forfeiture**: If a user violates any obligations, terms, policies, laws, or rules associated with their account or any Qoder service or product, Qoder reserves the right to immediately cancel, forfeit, and reclaim all issued benefits.
- **Campaign period**: This limited-time offer has a defined timeframe. Qoder reserves the right to terminate or modify this campaign or its terms at any time.
- **Changes**: Qoder reserves the right to change the terms, benefit structure, or eligibility criteria of this limited-time offer at any time. Any changes will be communicated by updating this document or through other means.
**Contact us**: If you have any questions, please reach out to [contact@qoder.com](mailto:contact@qoder.com).
### FAQ
**Q: When does the campaign end?**
The campaign ends on August 3, 2026 at 10:00 (UTC+8).
**Q: Are other model tiers also at 90% off?**
No. This campaign applies exclusively to the Qwen3.8-Max-Preview model.
**Q: Can free-tier users participate?**
New users receive a 14-day Pro Trial (with 300 Credits) upon first login to Qoder. The discount applies automatically during the Pro Trial period. Free-tier users outside the Pro Trial period or with exhausted Credits are not eligible.
**Q: Can I enjoy the discount if I subscribe or upgrade now?**
Yes. Any new subscription or upgrade to Pro / Pro+ / Ultra during the campaign period automatically qualifies.
**Q: Why do I see other charges in my Credits breakdown after selecting Qwen3.8-Max-Preview?**
The Experts mode in Qoder IDE and certain sub-Agent calls to specific models during tasks are billed at regular rates and shown transparently in the Credits breakdown.
## Off-Peak Discount Benefit: Up to 98 Percent Off
To help developers and knowledge workers make the most of off-peak compute hours, the Qwen3.8-Max-Preview model offers time-based Credits multiplier discounts: up to 98% off during off-peak hours (22:00–08:00 daily, UTC+8); Qwen3.8-Max-Preview also enjoys 90% off during regular hours, ensuring all-day savings. Automatically applies for Pro Trial and paid users — no sign-up required.
### Discount Overview
Times are based on Singapore Time (SGT, UTC+8), including weekends and public holidays. Other models not listed above are billed at standard rates. Discounts only affect Credits pricing — model quality is unchanged.
| **Model** | **Standard rate** | **Regular hours (08:00–22:00)** | **Off-peak hours (22:00–08:00)** |
| ------------------- | ----------------- | ------------------------------- | -------------------------------- |
| Qwen3.8-Max-Preview | 0.5x | 0.05x (90% off) | 0.01x (98% off) |
### Campaign Details
- **Start date**: July 19, 2026
- **End date**: August 3, 2026 at 10:00 (UTC+8)
- **Products**: Qoder IDE / Qoder JetBrains Plugin / Qoder CLI / QoderWake / Qoder Cloud Agents / Qoder Mobile/Web App
- **Eligible users**: Pro / Pro+ / Ultra / Pro Trial, as well as Teams and Enterprise users.
- **Model tier**: Qwen3.8-Max-Preview
- **Activation**: Automatic after updating to the latest version — no action needed
### How to Use
1. Update Qoder to the latest version
2. Switch to Qwen3.8-Max-Preview in the model tier selector
3. Initiate requests during the applicable time window — the discount applies automatically.
### Global Timezone Reference
Off-peak hours are based on Singapore Time (SGT, UTC+8). Below are the corresponding local times for major time zones:
Times below are based on 2026 Northern Hemisphere daylight saving time. During winter time some regions shift by 1 hour — use the UTC window (14:00–00:00 UTC) as the definitive reference.
| **Timezone** | **Off-peak (local time)** | **Regular (local time)** | **Off-peak covers** |
| :-------------------------------------- | :------------------------ | :----------------------- | :------------------------- |
| US Pacific PDT (UTC-7) | 07:00–17:00 | 17:00–07:00 | Weekday daytime |
| US Eastern EDT (UTC-4) | 10:00–20:00 | 20:00–10:00 | Daytime to early evening |
| UK BST (UTC+1) | 15:00–01:00 (+1) | 01:00–15:00 | Afternoon to early morning |
| Central Europe CEST (UTC+2) | 16:00–02:00 (+1) | 02:00–16:00 | Afternoon to late night |
| India IST (UTC+5:30) | 19:30–05:30 (+1) | 05:30–19:30 | Evening to early morning |
| Singapore / Hong Kong / Beijing (UTC+8) | 22:00–08:00 | 08:00–22:00 | Night to early morning |
| Japan / Korea JST (UTC+9) | 23:00–09:00 | 09:00–23:00 | Late night to morning |
| Australia Eastern AEST (UTC+10) | 00:00–10:00 | 10:00–00:00 | Midnight to morning |
### Other Terms
- **Non-transferable**: Discounts are non-transferable and cannot be redeemed for cash.
- **Credits count toward quota**: Credits consumed during discount periods count toward the monthly plan quota — they are not bonus credits.
- **Cancellation/Forfeiture**: If a user violates any obligations, terms, policies, or laws associated with their account or Qoder services, Qoder reserves the right to immediately cancel, forfeit, and/or reclaim all issued benefits.
- **Changes**: Qoder reserves the right to terminate or modify this campaign or its terms at any time. Changes will be communicated by updating this document or through other means.
**Contact us**: If you have any questions, please reach out to [contact@qoder.com](mailto:contact@qoder.com).
### FAQ
**Q: When does the campaign end?**
The campaign ends on August 3, 2026 at 10:00 (UTC+8).
**Q: Which models are discounted?**
Off-peak hours (22:00–08:00 UTC+8): Qwen3.8-Max-Preview enjoys the exclusive off-peak discount.
Regular hours (08:00–22:00 UTC+8): Qwen3.8-Max-Preview enjoys the 90% off rate.
**Q: Can I still get the discount after my Credits are exhausted?**
No. Once Credits are exhausted you need to upgrade your plan, purchase a resource pack, or wait for the next billing cycle.
**Q: Does model quality change during discount hours?**
No. The model is identical — reasoning capability and context length remain the same. Only the Credits pricing is affected.
**Q: Do Credits consumed during discount hours count toward my monthly quota?**
Yes. The discount lowers the Credits multiplier — it is not a bonus. Consumption still counts toward your monthly plan quota.
**Q: Can free-tier users participate?**
New users receive a 14-day Pro Trial (with 300 Credits) upon first login to Qoder. The discount applies automatically during the Pro Trial period. Free-tier users outside the Pro Trial period or with exhausted Credits are not eligible.
**Q: Can I participate if I subscribe or upgrade now?**
Yes. Subscribe or upgrade at any time during the campaign — the discount applies automatically when using covered models during applicable time windows.
Hours: Every night 22:00 to 08:00 next day (UTC+8), weekends and holidays included.
Coverage: All Qoder family products — international, China, personal, and Teams editions — including Qoder IDE, JetBrains Plugin, Qoder CLI, QoderWake, Cloud Agents, and Mobile.
Savings: Switch to Qwen3.8-Max-Preview and the Credits multiplier drops from 0.5× to 0.01× — that's 98% off. Model quality stays the same; only the pricing changes. Usage: Select Qwen3.8-Max-Preview in the model selector, send requests during off-peak hours, and the discount applies automatically. No sign-up needed, no redemption code — Pro Trial, Pro, and Teams users all qualify automatically.
# Ultimate for Free — Starter Pack + Booster Pack
The most powerful tier, free to use. From now until July 31, all Personal-plan users can claim **200 free Ultimate Starter Pack** calls in-app. After claiming the Starter Pack, paid / previously-paid users and those selected by Qoder will automatically receive a **1000-call Ultimate Booster Pack**.
July 27 – July 31: Booster Pack quota **resets to 1000 calls every day at 14:00 (UTC+8)** for 5 consecutive days. Hand the hardest jobs to the strongest tier.
Ultimate is Qoder's highest-capability tier, continuously running the industry's frontier-class models — built for long-context reasoning, multi-file refactors, architecture-level design, and other demanding engineering tasks. This time we're letting all users try it for free — open Qoder, claim, and start.
## What's Included
- **Period**: From now until July 31, 2026, 23:59 (UTC+8). Both claiming and usage end at this time.
- **Products**: Qoder IDE / JetBrains plugin / Qoder CLI
- **Eligible users**: All Personal-plan users
### Tier 1: 200-Call Ultimate Starter Pack (Manual Claim)
- **Who**: All Personal-plan users
- **How to get it**: Claim in-app, no prerequisites, use immediately
- **Limited to one claim per user during the campaign**
### Tier 2: 1000-Call Ultimate Booster Pack (Auto-Granted)
- **Who** (meet any one condition):
- Paid users or users with prior payment history — automatically granted
- Non-paid users — granted at Qoder's discretion based on account activity
- **Trigger**: You must first claim the 200-call Starter Pack; the system then auto-grants the Booster Pack — no extra action required
- **Daily reset (Jul 27–31)**: From July 27 until the campaign ends, the Booster Pack quota **resets to 1000 calls every day at 14:00 (UTC+8)**, for 5 consecutive days (5 resets total). Regardless of how many calls remain from the previous day, the quota automatically updates to 1000 — no action needed.
### Notes
- **Total quota**: The overall campaign quota is limited, first-come first-served. If the Starter Pack quota runs out early, the claim channel will close ahead of schedule with an announcement via official channels
- **Consumption**: On the Ultimate tier, free calls are deducted first; once used up, billing falls back to your plan's Credits / resource packs as normal
## How to Claim (Starter Pack)
Only the Starter Pack (200 calls) requires manual claiming. The Booster Pack (1000 calls) is automatically granted after you claim the Starter Pack — no extra action needed.
1. Update Qoder to the latest version (IDE / JetBrains plugin / CLI).
2. Sign in and claim:
- CLI: eligible users can claim and check usage with the `/claim-ultimate` command.

- JetBrains plugin: usage panel at the top-right of the Qoder plugin → click Claim.
- IDE:
- Usage panel at the bottom-right of the Editor window → click Claim.
- Usage panel at the bottom-left of the Quest window → click Claim.

3. Switch to the Ultimate tier and start using it.
## Other Terms
- **Non-Transferability**: Benefits are non-transferable and cannot be redeemed for cash.
- **Cancellation & Reclamation**: If a user violates any obligations, terms, policies, laws, or rules related to their account or any Qoder service or product, Qoder reserves the right to immediately cancel, void, and reclaim any issued benefits.
- **Changes to the Promotion**: Qoder reserves the right to change the terms, benefit structure, or eligibility criteria of this limited-time offer at any time. Any changes will be communicated by updating this document or through other forms of notification.
**Contact Us**: If you have any questions, please contact us at [contact@qoder.com](mailto:contact@qoder.com).
## FAQ
**Q: Who can get free calls?**
All Personal-plan users can claim the Ultimate Starter Pack (200 calls) in-app. After claiming, paid users, previously-paid users, and those selected by Qoder based on account activity will have the Ultimate Booster Pack (1000 calls) auto-granted by the system — no extra claiming needed. The Starter Pack claim entry appears in the **Usage** panel; if you don't see it, your account doesn't currently meet the conditions. For accounts with abnormal registration or usage behavior, Qoder reserves the right to revoke eligibility and granted quota. Qoder reserves the right of final interpretation of this campaign.
**Q: What's the relationship between the Starter Pack and the Booster Pack?**
The Starter Pack (200 calls) is for all Personal-plan users and must be claimed manually in-app. After claiming, eligible users automatically receive the Booster Pack (1000 calls) from the system. The two are used cumulatively.
**Q: What does "daily reset" mean for the 1000-call Booster Pack?**
From July 27 to July 31, users with the Booster Pack will have their quota **reset to 1000 calls every day at 14:00 (UTC+8)**, for 5 consecutive days (5 resets total). Regardless of how many calls were used the previous day, the quota automatically resets to 1000 — no action needed.
**Q: I'm an existing Free-tier user — can I claim?**
You can claim the Starter Pack (200 calls). Whether you receive the Booster Pack (1000 calls) depends on whether you're a paid / previously-paid user, or whether you've been selected by Qoder for a targeted grant.
**Q: When do the free calls expire?**
All free calls expire on July 31, 2026, 23:59 (UTC+8); any unused calls are forfeited. If you claim close to the deadline, your usable time is shorter accordingly, so claim and use them early.
**Q: Which is deducted first — free calls or plan Credits?**
On the Ultimate tier, free calls are deducted first; once used up, billing falls back to your plan's Credits as normal. Other tiers do not consume free calls.
**Q: Can Teams plan users participate?**
This campaign is for Personal-plan users only; Teams plans are not included this round.
**Q: What if I can't find the claim entry?**
First update your client to the latest version and make sure you're signed in. If your account meets the conditions but you still don't see the entry, contact official support.
**Q: If I upgrade to a paid plan after claiming the free calls, can I get the 1000-call Booster Pack?**
Yes. Once you become a paid user you're eligible for the Booster Pack. As long as you've already claimed the 200-call Starter Pack, the system will auto-grant it.
# Ultimate — Limited-Time Discount
Ultimate is Qoder's strongest built-in model tier, continuously running the industry's frontier-class models — purpose-built for the hardest engineering jobs: long-context reasoning, cross-file refactors, architecture-level design. This upgrade brings notable gains in both code understanding and engineering execution. To celebrate the upgrade, Ultimate is now available at a limited-time discount.
## What's Included
- **Starts**: July 7, 2026
- **Ends**: July 31, 2026, 23:59
- **Products**: Qoder IDE / Qoder JetBrains plugin / Qoder CLI
- **Eligible users**: All Qoder users
- **Tier**: Ultimate model tier
- **Offer**:
- Individual plans: including Free, Pro, Pro+, and Ultra — Ultimate at 50% off (billing multiplier drops from 1.6x to 0.8x)
- Enterprise plans: including Teams and Enterprise — Ultimate at 20% off (billing multiplier drops from 1.6x to 1.28x)
- **Activation**: Automatic. No claim, no setup required.
- **Please note**: Experts mode in Qoder IDE, as well as some tasks that involve sub-agents calling specific models, are not covered by the discount; these are shown accurately in your credits breakdown.
## How to Use It
1. Update Qoder to the latest version (IDE / JetBrains plugin / CLI)
2. Switch to Ultimate in the model tier selector
## Other Terms
- **Non-Transferability**: Benefits are non-transferable and cannot be redeemed for cash.
- **Cancellation & Reclamation**: If a user violates any obligations, terms, policies, laws, or rules related to their account or any Qoder service or product, Qoder reserves the right to immediately cancel, void, and reclaim any issued benefits.
- **Promotion Period**: This limited-time offer has specific start and end dates. Qoder reserves the right to terminate or adjust this promotion or its terms at any time.
- **Changes to the Promotion**: Qoder reserves the right to change the terms, benefit structure, or eligibility criteria of this limited-time offer at any time. Any changes will be communicated by updating this document or through other forms of notification.
**Contact Us**: If you have any questions, please contact us at [contact@qoder.com](mailto:contact@qoder.com).
## FAQ
**Q: Do other model tiers also get the discount?**
No. This campaign applies to the Ultimate tier only.
**Q: Are Add-on Credits covered?**
Yes. During the campaign, Add-on Credits on the Ultimate tier are also billed at the discounted rate.
**Q: I selected the Ultimate tier — why are there other billing items in my credits breakdown?**
Some tasks (e.g. those involving sub-agents) automatically call specific models to complete the work. These calls are billed at the standard rate and shown accurately in the breakdown.
# Premium Model Discount Rates
To help developers and knowledge workers get more from every Credit, Qoder offers time-based Credits multiplier discounts on selected premium models: during Off-Peak hours (14:00–00:00 UTC daily), savings reach up to 80%; Qwen3.8-Max is now available with an exclusive Off-Peak rate of 50% off. Pro Trial and paid users are automatically eligible. No signup required.
## Rates at a glance
| Model | Standard | Regular hours (00:00–14:00 UTC) | Off-Peak hours (14:00–00:00 UTC) |
| ------------ | -------- | ------------------------------------- | -------------------------------------- |
| Qwen3.8-Max | 0.5x | No discount | 0.25x (50% off) |
| Qwen3.7-Max | 0.5x | No discount | 0.1x (80% off) |
| Qwen3.7-Plus | 0.1x | 0.1x | 0.04x (60% off) |
| GLM-5.2 | 0.6x | 0.6x | 0.5x |
The canonical windows are defined in UTC. Weekends and public holidays are included. Other models are billed at standard rates. Discounts affect Credits pricing only; model quality is unaffected.
## Discount period
| Discount program | Start | End |
| ------------------------------------- | ------------------------ | --------------------------------------- |
| Qwen3.8-Max Off-Peak discount | August 3, 2026 | Not yet announced; advance notice given |
| Qwen3.8-Max-Preview Off-Peak discount | July 19, 2026 | August 3, 2026, 00:00 UTC |
| Qwen 3.7 Off-Peak discount | June 23, 2026 | Not yet announced; advance notice given |
| Qwen3.7-Max Regular-hours 50% off | June 25, 2026 | August 3, 2026, 00:00 UTC |
| GLM-5.2 Off-Peak discount | July 14, 2026, 14:00 UTC | August 15, 2026, 00:00 UTC |
## Eligibility
- **Users covered**: Pro Trial / Pro / Pro+ / Ultra / Teams
- **Products covered**: Qoder IDE / QoderWork / Qoder JetBrains Plugins / Qoder CLI / QoderWake / Qoder Cloud Agents / Qoder Mobile/Web App
- **Activation**: Automatic. Update to the latest version. No code, opt-in, or signup required.
## How to use
1. Update Qoder to the latest version.
2. Switch to Qwen3.8-Max, Qwen3.7-Max, Qwen3.7-Plus, or GLM-5.2 in the model selector.
3. Make requests during the applicable window. The discount applies automatically.
## Local hours
The canonical Off-Peak window is **14:00–00:00 UTC** daily. Regular hours are **00:00–14:00 UTC** daily.
Times below reflect 2026 northern-hemisphere summer (DST). During winter, some regions shift by 1 hour. The UTC window is always exact.
| Your timezone | Off-Peak hours (local) | Regular hours (local) | Off-Peak coverage |
| :------------------------------- | :--------------------- | :-------------------- | :-------------------------- |
| US West PDT (UTC-7) | 07:00–17:00 | 17:00–07:00 | Your workday |
| US East EDT (UTC-4) | 10:00–20:00 | 20:00–10:00 | Workday into evening |
| UK BST (UTC+1) | 15:00–01:00 (+1) | 01:00–15:00 | Afternoon to after midnight |
| EU Central CEST (UTC+2) | 16:00–02:00 (+1) | 02:00–16:00 | Afternoon to late night |
| India IST (UTC+5:30) | 19:30–05:30 (+1) | 05:30–19:30 | Evening to early morning |
| Singapore / HK / Beijing (UTC+8) | 22:00–08:00 | 08:00–22:00 | Evening to morning |
| Japan / Korea JST (UTC+9) | 23:00–09:00 | 09:00–23:00 | Night to morning |
| Australia East AEST (UTC+10) | 00:00–10:00 | 10:00–00:00 | After midnight to morning |
## Terms
- **Non-transferable**: This discount is non-transferable and cannot be exchanged for cash.
- **Credits count toward allowance**: Credits consumed during discount windows count toward your monthly plan allowance. They are not bonus Credits.
- **Cancellation/forfeiture**: If you violate any obligation, term, condition, policy, law, or rule related to your account or any Qoder service or product, Qoder reserves the right to immediately cancel, forfeit, and/or recover all benefits granted.
- **Changes**: Qoder reserves the right to terminate or modify this activity or change its terms, discount structure, or eligibility criteria at any time. Any changes will be communicated by updating this document or through other means.
**Contact us**: If you have any questions, please reach out at [contact@qoder.com](mailto:contact@qoder.com).
## FAQ
**Q: When does this activity end?**
See the Discount period table above for each program. The Qwen3.8-Max and Qwen 3.7 Off-Peak discounts have no announced end date; we will notify you in advance through the Qoder website, email, X, and other official channels. The GLM-5.2 Off-Peak discount ends on August 15, 2026, at 00:00 UTC.
**Q: Which models are eligible for discounts?**
During Off-Peak hours (14:00–00:00 UTC): Qwen3.8-Max, Qwen3.7-Max, Qwen3.7-Plus, and GLM-5.2. Other models are not part of this activity.
**Q: How is GLM-5.2 priced after its discount ends?**
After the Off-Peak discount ends, GLM-5.2 is billed at its standard 0.6x multiplier around the clock.
**Q: Can I still get the discount after my Credits are exhausted?**
No. You will need to upgrade your plan, purchase an add-on pack, or wait for the next billing cycle.
**Q: Is model quality affected during discount windows?**
No. Same model, same reasoning, same context length (user configurable). The discount affects Credits pricing only.
**Q: Do Credits consumed during discount windows count toward my monthly allowance?**
Yes. The discount reduces the Credits multiplier; it does not grant bonus Credits. Usage still counts toward your plan allowance.
**Q: Can Community (free) plan users participate?**
New users receive a 14-day Pro Trial with 300 Credits upon first login to Qoder. Pro Trial users are automatically eligible and get discounted rates when using covered models during the applicable windows. Community users who are not on Pro Trial, or who have exhausted their Credits, are not eligible.
**Q: If I subscribe or upgrade now, can I get the discount?**
Yes. Any subscription or upgrade during the activity period automatically qualifies. Use a covered model during the applicable window to get the discount.
# IDE Overview
Qoder ( /ˈkoʊdər/ ) is an agentic coding platform designed for real software development. It seamlessly integrates enhanced context engineering with intelligent agents to gain a comprehensive understanding of your codebase and systematically tackles software development tasks.
Qoder IDE offers two primary workspaces—**Editor** and **Quest**:
- **Editor** keeps NEXT, Inline Chat, and the Chat panel alongside your code for in-flow collaboration and rapid iteration.
- **Quest** is a dedicated window for **autonomous delegation**: hand off long-running, multi-step work to agents, with task boards, progress tracking, and artifact review in one workspace.
Switch between them whenever you want to pair "code with me" with "run it for me".
Beyond these workspaces, Qoder IDE brings together code generation, Q\&A, multi-file edits, and agentic automation—so you can think deeper, move faster, and build with more confidence in real software projects.
Install Qoder IDE and begin coding with AI assistance in minutes.
Stay up to date with the latest features, enhancements, and bug fixes.
Access the latest installers for your platform.
**Autonomous delegation** in a dedicated window—hand off long-running, multi-step work to agents, and track board, status, and artifacts in one workspace.
Extend Qoder IDE’s capabilities by connecting to external tools and services via Model Context Protocol (MCP) servers.
Knowledge automatically accumulates and manages business knowledge from your daily development.
Bring agentic coding to JetBrains IDEs, empowering developers to command AI agents without leaving their IDE.
Build, code and automate complex tasks without ever leaving your terminal or workflow.
# Quick Start
This topic walks you through a hands-on project using Qoder's core features as an individual user. By the end, you'll know how to use **NEXT** (next-edit suggestions), **Inline Chat**, and **Ask / Agent** in the Chat panel. When you need **autonomous delegation** for long-running, multi-step work, open the **Quest** window—let agents carry execution forward while you track board, progress, and artifacts in one workspace. These are the main entry points for AI-assisted coding and delegation. See [Chat overview](./user-guide/chat/overview), [NEXT](./user-guide/next-edit-suggestion), [Inline Chat](./user-guide/inline-chat), and [Quest overview](./user-guide/quest/overview).
Qoder Individual Edition is currently available as a free trial for all users. The trial duration is subject to change. For the latest information, please check product updates.
1. Download the installer from [https://qoder.com/download](https://qoder.com/download).
2. Double-click the file to begin installation.
3. Launch Qoder by double-clicking the Qoder IDE icon.
1. In the upper-right corner of your Qoder IDE, click the user icon or use the keyboard shortcut (`⌘` `⇧` `,` (macOS) or `Ctrl` `Shift` `,` (Windows)), and select **Sign in**.
2. On the web page that appears:
- Click **Sign up** at the bottom and complete the registration process, or
- Use your Google or GitHub account to sign up directly.
3. Return to the Qoder IDE. You're now signed in and ready to start.
Choose to work with a local project or clone a sample from GitHub.
- **Use a local project**
1. Click **Open** or use the keyboard shortcut:
- macOS: `⌘` `O`
- Windows: `Ctrl` `O`
2. Browse to your project folder, select a file, and open it.
- **Clone a project**
1. Click **Clone repo**.
2. In the search bar at the top:
- Enter a project URL and click **Clone from URL**, or
- Click **Clone from GitHub** and follow the prompts.
3. Complete the steps to clone the project.
- **Use NEXT (next-edit suggestions)**
NEXT surfaces context-aware edit suggestions at your cursor to kick off AI-assisted coding.
1. Type partial code or a natural-language request—for example, "Initialize a list."
2. Press `⌥` `P` (macOS) or `Alt` `P` (Windows) to show suggestions.
3. Press **Tab** to accept the current suggestion.
NEXT supports multi-line edits and smooth completion. For full behavior, see [NEXT](./user-guide/next-edit-suggestion).
- **Open Inline Chat**
Use Inline Chat to get AI help in your code context.
1. In the editor, press `⌘` `I` (macOS) or `Ctrl` `I` (Windows) to open Inline Chat.
2. Enter your request and send—for example, "Add a method for handling file updates."
3. Press `⌘` `⏎` (macOS) or `Ctrl` `Enter` (Windows) to apply generated code.
See [Inline Chat](./user-guide/inline-chat).
- **Use Ask / Agent in Chat**
Press `⌘` `L` (macOS) or `Ctrl` `L` (Windows) to open **Chat**, then choose **Ask** or **Agent** in the toolbar for larger tasks.
1. Enter a request on the right—for example, "Create tests for this function and run them."
2. After sending, follow Ask or Agent prompts to apply changes or run commands.
3. Use **Run** or confirm actions as the UI suggests.
**Ask** is Q\&A–first; **Agent** suits multi-file implementation.
- **Open Quest**
**Quest** is for **autonomous delegation**: start long-running, multi-step tasks in a dedicated window, let agents keep execution moving, and review board, status, and deliverables in one workspace. See [Quest overview](./user-guide/quest/overview).
# Model Selector
Qoder IDE includes world-class SOTA AI models and offers a flexible selection mechanism to help you find the optimal balance between development efficiency, output quality, and cost.
In addition to built-in models, you can also connect your own models via API keys. See [Custom Models](/user-guide/chat/custom-models) for details.
## Model Selector
The Model Selector offers two selection methods: **Tier Selection** and **Specific Model**, to meet different scenario needs.
### Tier Selection
The Model Tier Selector provides developers with five high-performance model pools, each striking a different balance between cost and performance. Like driving modes in a smart car, choose the right gear for each task.
| **Tier** | **Description** | **Use Cases** | **Credit Usage** |
| ------------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------- |
| **Auto (Smart Routing)** | Intelligently selects the most suitable model, balancing performance and cost | Most daily development work, recommended as default | \~1.0× |
| **Ultimate** | Expert-level deep reasoning and thinking capabilities | Complex system design, high-difficulty problem analysis | \~1.6× |
| **Performance** | Advanced reasoning capabilities, high-quality output | Core feature implementation, architecture design, code refactoring | \~1.1× |
| **Efficient** | Standard reasoning capabilities, high cost-effectiveness | Basic code generation, unit tests, daily Q\&A | \~0.3× |
| **Lite** | Basic reasoning capabilities, free to use | Quick validation, basic logic implementation, quick Q\&A | Free |
Lite mode may have slower response times during peak hours and does not currently support multimodal Q\&A.
#### Credit Consumption Comparison
The table below shows Credit consumption examples for different tiers when completing a moderately complex coding task:
| **Model Tier** | **Credit Consumption Rate** | **Example Task Consumption** |
| -------------- | --------------------------- | ---------------------------- |
| Auto | \~1.0× | 10 Credits |
| Ultimate | \~1.6× | 20 Credits |
| Performance | \~1.1× | 11 Credits |
| Efficient | \~0.3× | 3 Credits |
| Lite | Free | 0 Credits |
> Due to variations in tasks and codebases, actual consumption rates may differ.
Experts Mode is selected separately from model tiers. In Experts Mode, you can choose between **Auto (1.0x)** and **Ultimate (1.6x)** tiers. It coordinates multiple expert agents in parallel, so actual Credit usage depends on task complexity, expert turns, and tools invoked.
### Specific Model
In addition to tier selection, you can directly choose a specific model from a particular provider. Ideal for scenarios where you have clear model preferences or specific requirements.
> Currently, only a selection of models is available for direct selection.
| **Model Name** | **Description** | **Credit Consumption Rate** |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------- |
| Qwen3.8-Max | Qwen's latest foundation model, with 2.4T parameters, leading in software engineering, office work, and deep reasoning | 0.5× |
| Qwen3.7-Max | Qwen's latest model, with top-tier agentic capabilities, autonomously handles complex tasks up to 35 hours long | 0.5× |
| Qwen3.7-Plus | Comprehensive leap in reasoning capability, efficiency, and multimodal experience | 0.1× |
| DeepSeek-V4-Pro | Excels at complex reasoning, code generation, and engineering tasks | 0.8× |
| DeepSeek-V4-Flash | Fast reasoning and low cost with balanced capabilities | 0.3× |
| GLM-5.3 | Zhipu's open-source flagship model, with coding capabilities competitive with leading international models, plus security review and vulnerability reasoning | 0.6× |
| GLM-5.2 | Excels at complex systems engineering and long-horizon tasks | 0.6× |
| Kimi-K3 | Kimi's most powerful model, with 2.8T parameters, built for software engineering, knowledge work, and deep reasoning | 0.8× |
| Kimi-K2.7-Code | Kimi's latest model, purpose-built for long-context coding: precise instruction following, reliable long-horizon execution | 0.3× |
| MiniMax-M3 | Native multimodal perception, frontier coding, and 1M context depth for highly demanding workflows | 0.2× |
The rates in the table are overall estimates. Actual Credit usage can vary with parameter settings: changing the context window, Thinking Effort, or speed may change the rate. **DeepSeek-V4-Pro** and **DeepSeek-V4-Flash** also use peak-valley pricing. Final charges are based on actual usage.
### Model Parameters
Some models support configuring parameters to better adapt to different task types. In the model selector dropdown, hover over a model name to reveal a parameter panel on the left, then click the **Edit** button to configure parameters.
**Kimi-K2.7-Code** exposes a **Fast** toggle in its parameter panel. Turning it on delivers \~6× response speed, with the Credit rate rising from 0.3× to 0.6×.
#### Context
Controls the maximum context window size available for the conversation.
| **Option** | **Description** |
| ---------- | -------------------------------------------------------------- |
| 200K | Standard context window, sufficient for most tasks |
| 400K | Extended context for larger codebases or lengthy conversations |
| 1M | Maximum context for extremely large-scale projects |
#### Thinking Effort
Controls how deeply the model reasons before generating a response. Available options vary by model — the interface will show the supported levels after you select a model.
| **Option** | **Description** |
| ---------- | ------------------------------------------------------------- |
| low | Minimal reasoning, fastest responses |
| medium | Balanced reasoning depth |
| high | Thorough reasoning for complex tasks |
| xhigh | Deep analysis for high-difficulty problems |
| max | Maximum reasoning depth, best for the most complex challenges |
#### Supported Models
Currently, Ultimate, Performance, DeepSeek-V4-Pro, DeepSeek-V4-Flash, Qwen3.8-Max, Qwen3.7-Max, Qwen3.7-Plus, GLM-5.3, GLM-5.2, MiniMax-M3, Kimi-K3, and Kimi-K2.7-Code support parameter configuration. Qwen3.7-Max, Qwen3.7-Plus, and MiniMax-M3 support Context only; Kimi-K2.7-Code only supports enabling Fast Mode; the others support both Context and Thinking Effort.
### How to Switch
1. In the AI Chat input box, click the model selector dropdown menu
2. Select **Model Tier** or **Specific Model**
3. The selection takes effect immediately, and the new model will apply to subsequent conversations in the current session
When your account has no Credits, only the Lite tier is available. Upgrade or acquire more Credits to unlock other tiers.
## FAQ
### Will the model list be updated?
Yes. Qoder IDE continuously introduces outstanding new models from the industry, and will retire or replace some older models based on model performance and market conditions, keeping the model list high-quality and reliable.
### Can I switch models within the same conversation?
Yes. You can switch model tiers or specific models at any time using the dropdown menu in the chat input box. The new selection takes effect instantly for subsequent conversations, allowing you to adjust dynamically based on real-time task needs.
### What's the difference between model tiers and specific models?
The Model Tier Selector intelligently matches the most suitable model based on the selected tier—you don't need to know which specific model is being used. Specific model selection lets you directly choose a particular model from a specific provider, ideal for scenarios where you have clear preferences or specific requirements.
### How is Credit consumption calculated for different models?
Your Credit consumption is determined by the number of tokens used per request and the unit price of the model used. For detailed billing rules, please refer to [Credits](/Credits).
### Is Lite mode completely free? Are there any limitations?
Lite mode is currently free, but responses may be slower during peak hours, and it does not yet support multimodal Q\&A.
# Custom Models
Qoder IDE supports accessing third-party provider model resources via API keys.
**Applicable For**: Users with Individuals plans
**Supported Providers**: Alibaba Cloud Model Studio, DeepSeek, Z.ai, Kimi, MiniMax, Xiaomi MIMO
**Special Note**:
Repo Wiki uses a fixed model and is billed separately. When generating, there will be a prompt notifying you of the additional credit consumption.
## Adding Custom Models
Open **Qoder IDE Settings**.
Select **Models** in the left navigation.
Click **+ Add**, select a provider and the model you need, then enter your API key.
Click **Get API Key** to open the provider's key management page.
Click **Add**. The system automatically verifies the connection status.
After configuration, select the configured model in the chat interface to start using it.
## Managing Custom Models
In the "Models" panel, you can perform the following operations on custom models:
| **Operation** | **Description** |
| -------------- | ------------------------------------------------------------ |
| Edit | Modify model name alias |
| Delete | Remove model, cannot be used after deletion |
| Enable/Disable | Control whether the model is displayed in the selection list |
## FAQ
### 1. Does using custom models consume Credits?
Custom model fees are billed directly to your provider API account and do not use Qoder Credits. However, Repo Wiki uses a fixed model and consumes Qoder Credits. A prompt appears when generating content.
### 2. How to obtain API keys?
Provider API key URLs:
- **DeepSeek**: [platform.deepseek.com](https://platform.deepseek.com/)
- **GLM**: [open.bigmodel.cn](https://open.bigmodel.cn/)
- **Kimi**: [platform.moonshot.cn](https://platform.moonshot.cn/)
- **MiniMax**: [platform.minimaxi.com](https://platform.minimaxi.com/)
- **Xiaomi MIMO**: [platform.xiaomimimo.com](https://platform.xiaomimimo.com/)
- **Alibaba Cloud Model Studio**: [bailian.console.aliyun.com](https://bailian.console.aliyun.com/)
### 3. What to do if adding a model fails?
Please check the following:
1. Whether the API key is correct with no extra spaces
2. Whether the API key has expired or been disabled
3. Whether the provider account has sufficient balance
4. Whether the network connection is normal
### 4. Can I add multiple models from the same provider?
Yes. You can add different versions of models from the same provider or use different API keys.
# Overview
**Editor** is Qoder IDE’s core AI workspace in the IDE: you get real-time code predictions and completions through [**Next Edit Suggestion**](/user-guide/next-edit-suggestion) while coding, and can use **Ask** or **Agent** in the chat panel for questions, edits, and multi-step work.
## Start a new chat
### Open the chat panel
After signing in to Qoder IDE, click the toggle AI sidebar button in the top right corner to open the chat panel.
You can also use the shortcut:
| Action | macOS | Windows |
| :---------------------- | :------ | :--------- |
| Open / close chat panel | `⌘` `L` | `Ctrl` `L` |
### View chat history
Click the history icon in the top right corner of the chat panel to view all chat history.
### Choose a mode
- [Ask](/user-guide/chat/ask): Q\&A mode that answers programming questions, provides solutions, and offers suggestions based on context, without modifying code.
- [Agent](/user-guide/chat/agent): Autonomous coding mode featuring self-decision making, environment awareness, and tool usage. Leveraging tools like project search, planning, file editing, and terminal operations, it completes coding tasks end-to-end. Supports MCP tool configuration to deeply integrate with your development workflow.
### Input requirements
After selecting a mode, describe your request in the input box. The following tips can help you achieve better results:
- **Structured requests**: Clearly state what you want Qoder IDE to do, outlining the goals and steps of your coding task.
- **Provide context**: Attach files, images, code changes, and other relevant information to help Qoder IDE understand the background and generate more accurate solutions.
- **Clear expectations**: Specify preferences or guidelines, such as programming language, coding standards, output format, or change objectives. For example: "When generating code changes, please add comments for each method."
- **Iterative feedback**: Provide feedback on code suggestions or answers. For complex tasks, break down the requirements and iterate step-by-step, collaborating with Qoder IDE to complete them.
## Next Edit Suggestion
In addition to interacting with AI in the Chat panel, Qoder IDE provides the [**Next Edit Suggestion**](/user-guide/next-edit-suggestion) feature seamlessly integrated into the code editor. Based on your current cursor position, context, and recent changes, it automatically predicts and generates the code you are likely to write next. Simply press `Tab` to quickly accept the suggestion, making your coding process much smoother.
## Separate chat windows
Separate chat windows allow you to split ongoing conversations into individual windows. When initiating multiple Agent tasks simultaneously, you can view the execution progress and results of each task in parallel, freeing you from switching back and forth between tabs.
### How to use
At the top of the Chat panel, right-click the conversation tab you want to separate, and select **Move into New Window** from the right-click menu. The conversation will open in an independent window.
The separated window is completely independent of the main window. You can freely adjust its size and position, distributing them flexibly across multiple screens.
### Use cases
- **Parallel multi-task monitoring**: When running multiple Agent tasks simultaneously, allocate different sessions to separate windows to monitor the execution status of each task in real time.
- **Split-screen comparison**: When you need to compare the output of two sessions, place them side-by-side in left and right windows for easy viewing.
## Recommendation cards
After the agent completes a task turn and replies, a set of recommendation cards will automatically appear at the end of the message. Based on current code changes, project status, and conversation context, these cards predict your most likely next step—click to populate it directly into the input box, ready to be sent or further edited. After the agent finishes execution, it will generate new recommendation cards based on the latest context.
Recommendation cards are triggered in Agent mode.
### Recommendation types
- **Review Code Changes**: Triggered after the agent completes code generation or modification, allowing you to review whether the new code meets project standards and check for potential defects.
- **Run Feature Test**: Triggered when changes to frontend files (.tsx, .jsx, .vue, .html, .css) are detected, enabling you to verify page rendering and interaction effects in the browser.
- **AI Suggestion**: Generated autonomously by the agent based on the current conversation context.
* Recommendation cards are inferred from context and may not exactly match your actual intent.
* Recommendation cards are only clickable on the latest agent reply; they will disappear from the previous turn once a new message is sent.
* Tasks triggered by clicking recommendation cards follow the billing rules of the model selected for the current session.
# Ask Mode
**Ask** is for “think first, change later”: Qoder IDE answers questions using read-only understanding of your repo context, explains trade-offs, and can suggest copy-pastable snippets. It **does not autonomously rewrite the whole workspace** the way **Agent** does. Great for design reviews, API learning, small examples, and planning refactors.
Ask can still comment on and optimize code, suggest fixes, and help troubleshoot build errors.
## Input expectations and tips
- **State the goal**: what problem you are solving and the shape of the answer you want (pseudo-code only vs production-ready).
- **State constraints**: language/runtime versions, performance or security boundaries, modules that must not change.
- **Attach context**: use `@` or send selections to chat; smaller scopes usually yield better answers.
- **Work in steps**: validate each step before asking for the next.
- **When you need runnable snippets**: specify environment and dependencies so the model does not assume a default stack.
## **Ask for help**
When you're unsure how to solve a coding problem, open the Chat panel by clicking the toggle AI side bar button in the top-right corner, or using the keyboard shortcut (`⌘` `L`(macOS)or`Ctrl` `L`(Windows)). Then, make sure the pull-down bar in the chat box is set to Ask mode.
To ask about specific code, highlight it with your cursor and click send to chat button or using the keyboard shortcut. You can also select entire files. Qoder IDE will then answer based on the information you gave it.
# Agent Mode
Agent Mode features autonomous decision-making, environment awareness, and tool utilization capabilities. It can leverage project search, file editing, terminal access, and other tools to execute coding tasks efficiently. Additionally, you can configure Model Context Protocol (MCP) tools to further extend the AI coding assistant's capabilities, making it even more aligned with development workflows.
The main difference between Agent Mode and Ask Mode is that Agent Mode can autonomously apply changes without requiring constant confirmation from you.
Agent Mode offers the following core features:
- Project-level changes: Based on task description, Agent Mode can autonomously break down tasks and modify multiple code files. Through multi-turn conversations, code optimization or snapshot rollbacks can be achieved to complete tasks more efficiently.
- Plan making: Based on your inputs, Agent Mode can create a step-by-step plan for you to review.
- Automatic environment awareness: Agent Mode automatically detects project frameworks, technology stacks, required code files, and error messages from task descriptions, eliminating the need to manually add project context.
- Tool utilization: Agent Mode autonomously uses various built-in tools, such as file read/write, code queries, and error troubleshooting. It also supports automatic discovery and use of MCP tools.
- Command execution: Agent Mode autonomously decides which commands to execute. It then generates these commands and runs them in the terminal.
## **Planning**
Agent autonomously recognizes intent and automatically generates a plan for complex tasks. The generated plan is presented for your review, and upon confirmation, execution proceeds according to the plan. For more details on how Planning works, see [Planning](./plan-agent).
For medium-to-large tasks that require strict alignment on technical solutions or involve complex steps, we recommend using the [Code with Spec](/user-guide/quest/spec-driven) mode in the Quest workspace to generate a structured document before writing code.
## **Make plans by to-dos**
Based on your inputs, Qoder IDE will generate a plan with To-dos for you to review, breaking down complex issues into manageable, sequential steps. If you would like to add more steps, just enter your requirements and Qoder IDE will add corresponding To-dos to the plan.
At the bottom of chats, you can view the progress of each task:
- Empty circle - Task has not yet started.
- Loading circle - Task is currently in progress.
- Checkbox - Task is completed.
## **Code modification and review**
### **Multi-file edits**
In Agent Mode, Qoder IDE might modify multiple code files. Each modification involves two stages: "Generating" and "Applying". You can check file statuses in the chat box or the Workspace:
- **Generating**: Producing code suggestions based on task breakdown.
- **Applying**: Integrating suggestions with original files to create change files.
- **Applied**: Code changes are completed and await review.
Click on a file to view the suggestion generation process and the change diff.
### **Review, accept, or reject modifications**
Click the **View Changes** button to compare modifications. Then:
- Use the up or down arrow to navigate and view changes in the current file.
- Accept or reject each change.
- Use the forward and backward arrows in the file-level operation area to switch between changed files.
- Accept or reject at the file level.
- Partially modify change files.
## **Multi-turn iterations**
### **Refine requirements in multiple turns**
In Agent Mode, after completing the current conversation and generating code changes, you can continue to refine your requirements by submitting additional queries. Qoder IDE will incorporate the previous code changes, analyze the updated requirements, and produce new code change files accordingly. If you need to undo all code changes generated in the current conversation, click the **Revert** button in the chat stream to trigger an automatic rollback.
## **Programming tools**
Agent Mode supports using built-in programming tools autonomously. These tools support file searching, file reading, directory traversal, semantic symbol retrieval, file modification, error message retrieval, commands execution, and more. Agent Mode can also plan its next steps based on the returned results.
## **Execute commands**
Agent Mode autonomously chooses and runs commands based on requirements. By default, commands must be confirmed before execution.
- Clicking **Run** submits the command for execution.
- Clicking **Cancel** skips the command.
For tasks running in the background, a "Running in Background" indicator will appear. Agent Mode continues working on other tasks and returns to check the output when needed.
An allowed list for automatic command execution can be configured in **Qoder IDE Settings**. Access **Qoder IDE Settings** via the user icon or keyboard shortcuts (`⌘` `⇧` `,` (macOS) or `Ctrl` `Shift` `,` (Windows)), and navigate to **Chat**. Multiple commands should be separated by commas.
## **MCP tools**
Qoder IDE's Agent Mode can integrate with MCP (Model Context Protocol) services. You can configure your own MCP services for the agent, extending the capabilities of the AI coding assistant to better fit your workflow.
The agent can also connect to third-party MCP service marketplaces to install the necessary MCP services with one click.
For more details, see [MCP](/user-guide/chat/model-context-protocol).
# NEXT Code Suggestion
> Predicts your intent and suggests the NEXT code.
NEXT helps you get started with AI-assisted coding by offering intelligent, context-aware edits right at your cursor.
With Qoder IDE NEXT, you can:
- Edit multiple lines at once near your cursor.
- Get suggestions based on recent changes and previously accepted edits.
- Navigate seamlessly within files to the next suggestions.
- Get automatic dependency import.
- Get cross-file modification suggestions, eliminating the need to search for related changes manually.
## **How it works**
Qoder IDE automatically displays suggestions either inline or side by side, depending on the width of the changed code and NEXT prompt:
- If the combined width exceeds your editor's width, suggestions appear inline.
- Otherwise, they are shown side-by-side for easier comparison.
To accept or reject a suggestion:
- Hover over **Accept**/**Reject**, or
- Press `Tab`to accept, `Esc` to reject.
If the next edit is outside your current view:
- Click **Tab to Jump** or press `Tab` to go to the edit location in the same file.
- For edits in other files, click **Tab to Jump** or press `Tab` to navigate to the edit location of the target file.
To preview the suggested changes
- Hold down the` `⌥` (Mac)`key /`Alt` (Windows) key to preview.
- Release to restore the original code.
## **Settings**
### Enable NEXT
1. In the upper-right corner of your Qoder IDE, click the user icon or use the keyboard shortcut (`⌘` `⇧` `,` (macOS)or`Ctrl` `shift` `,`(Windows)), and select **Qoder IDE Settings**.
2. In the panel that appears, click **NEXT**.
3. Turn on **NEXT**.
### Trigger When Commenting
NEXT is enabled in comment blocks by default. You can disable it in Settings.
### Auto import
When turn on, NEXT can automatically import necessary modules for typescript.
### Quick Settings
Click the NEXT icon in the bottom-right corner to access quick settings where you can:
1. Turn NEXT on or off globally.
2. Enable or disable NEXT for specific file extensions, e.g., markdown or plaintext.
## **Display behavior**
NEXT supports intelligent editing for deletions, modifications, and additions, with visual diffs tailored to the type of change.
## **Scenarios**
Here are some common scenarios that demonstrate how Qoder IDE NEXT can improve your coding efficiency:
- **Multi-point predictions within a single file**\
When you modify a variable or function name, NEXT automatically identifies all related usage points in the same file and suggests updates across multiple locations simultaneously.
- **Automatic dependency imports**\
As you write code that references external libraries or modules, NEXT automatically detects and adds the required import statements, eliminating manual imports.
- **Function-level autocompletion** \
NEXT predicts entire function implementations based on your context, generating complete function bodies with proper logic and structure rather than just line-by-line suggestions.
- **Cross-file edit predictions**\
When you make changes in one file, NEXT analyzes your codebase and proactively suggests related modifications in other files, saving you from hunting down dependencies manually.
# Inline Chat
Inline Chat lets developers converse directly in the code editor, so they can edit code in a single file.
## **Open inline chat**
- macOS: `⌘` `I`
- Windows: `Ctrl` `I`
## **Add context**
In the inline chat window, type `@` to add context. You can add files, rules. Select the context you want to mention, and Qoder IDE will consider it along with your request, then modify the current code file or answer your question.
## **Example scenarios**
### **Scenario 1: Modify code snippets**
To modify a code file or snippet, select it and open the inline chat window as described above. Enter your code modification requirements, such as adding comments or refactoring code. Qoder IDE will then generate code changes in the code editor.

### **Scenario 2: Add code snippets**
Open the inline chat window and enter your coding requirements. Qoder IDE will then generate code suggestions.

# Tools
Qoder IDE offers a rich set of tools covering programming scenarios such as file search, file reading, directory browsing, semantic symbol retrieval, file editing, error checking, and command execution. It can also integrate with Model Context Protocol (MCP) services, allowing developers to configure more extensions to further optimize the coding experience.
## **Search**
In Agent Mode, Qoder IDE uses search tools to retrieve information from the following scopes:
| **Scope** | **Description** |
| :---------- | :------------------------------------------------------ |
| Codebase | A code search tool for codebase exploration |
| Files | Searches for files within the project. |
| Code | Searches for specific code snippets within the project. |
| Directory | Views the project directory structure. |
| Web | Performs a free web search without requiring API keys. |
| Web content | Retrieves content from web pages. |
## **Edit**
In Agent Mode, Qoder IDE uses the following tools to modify code files:
| **Function** | **Description** |
| :----------- | :---------------------------------- |
| Modify files | Modifies specific code files. |
| View files | Displays the content of code files. |
## **Execute commands**
In Agent Mode, Qoder IDE uses the following tools to write and run commands based on earlier conditions.
| **Function** | **Description** |
| :------------------ | :------------------------------------------------- |
| Run a command | Executes commands in the terminal. |
| Get terminal output | Retrieves the output from previously run commands. |
## **Find problems**
In Agent Mode, Qoder IDE uses the following tool to find code problems.
| **Function** | **Description** |
| :---------------- | :-------------------------------------------------------------------- |
| Get code problems | Finds code issues within the project (in the \*\*Problem \*\*window). |
## **Update memories**
In Agent Mode, Qoder IDE uses the following tool to update memories according to your requirements:
| **Function** | **Description** |
| :-------------- | :--------------------------------------------- |
| Update memories | Updates persistent memory based on user input. |
## Diff view
Whenever AI suggests code modifications—whether through Agent Mode or Inline Chat—the changes are presented in a clear, contextual diff view so you can review them before applying. This gives you full visibility and control over every modification.
### Diff preview format
The preview displays changes using standard diff notation:
- Added lines are shown in green
- Removed lines are shown in red
- Unchanged surrounding code is displayed in a neutral tone, preserving context and helping you understand the scope of the change
This inline diff format helps you see exactly what will change, understand why the change is made, and assess how it fits into the existing codebase—then accept, edit, or reject each change with confidence.
Example:
```diff
function validate(user) {
- return user.id !== undefined;
+ return user.id && user.status === 'active'; }
```
### Review mode
After an Agent completes its task or a conversation turn, the system displays all modifications, providing a comprehensive overview of changes across the entire codebase. Since code changes are applied directly, any unsatisfactory modification can be reverted by clicking **Reject**.
#### Per-change controls
In the top-right corner of each change block, use **Reject** to discard that specific change.
#### File-level controls
At the bottom of the file:
- **Reject** to discard all suggested modifications in the current file
- **Navigate** between files that have pending changes

#### Handle multiple-file changes
When changes span multiple files, the affected file names appear above the Chat panel. Click **Reject All** to discard changes across all listed files (a secondary confirmation prompt prevents accidental operations); click a file name to jump to that file with diffs displayed; or hover over a file name to show **Reject** for that file only.
## Image generation
Type the `/gen-image` command in chat to generate images from a natural-language description; the Agent creates the image and returns a preview inline.
Generated images support:
- **Add to Chat** — add the image back into the conversation as context so the Agent can answer or produce follow-ups based on it.
- **Download** — save the image locally to plug straight into your design or authoring workflow.
- **Copy image** — copy the image to the clipboard for pasting elsewhere.
Also available in Quest.
## Message queue
The message queue lets you keep typing what to do next while the Agent is running a task. New messages enter a pending list and queue up in order, then run once the current task finishes. You can also trigger Steer on any message in the queue at any time to add direction or adjust requirements while the task is running.
The message queue is also available in Quest.
### Queuing and execution
While an Agent task is running, type into the input box and press Enter — the message appears as a new entry at the top of the pending list. When the current task finishes, the Agent automatically processes the queued messages in order, and the queue area collapses once the list is empty.
How the queue executes differs by mode:
- **Ask and Agent modes**: queued messages wait for the current turn to end by default, then run automatically in order. You can click the **Steer** button on any queued message at any time to have the Agent step in immediately.
- **Experts mode**: the Agent proactively decides when to batch-fetch and take over queued messages — no manual steering needed.
### Steer
Click the **Steer** button on a message in the queue to hand that content to the Agent immediately, letting it take on new direction or adjusted requirements mid-execution and reducing the cost of interruptions and restarts.
Once Steer is triggered, the model decides how to weave the input in based on the current task progress.
### Other queue actions
Hover over a message entry in the pending list to reveal its actions:
- **Drag to reorder**: adjust message order with the handle on the left; the new order takes effect immediately.
- **Edit**: the message content is loaded back into the input box; after editing, press Enter to update the entry in place, keeping its position.
- **Delete**: removes the message from the queue; the order of the remaining messages is unchanged.
# Overview
Quest has evolved into a dedicated window for agent-first workflows, bringing task management, status tracking, and artifact review into one place for a more focused delegation experience.
It integrates **Agent** and **Experts** sub-modes; you simply describe your goal, and the AI autonomously completes the development task — from requirement clarification to code delivery — progressing entirely within a unified task interface.
**Core philosophy: Define the goal. Review the result.**
## Core capabilities
Supports parallel advancement of multiple projects and tasks, completing coordination, command, and execution in a unified interface, significantly improving R\&D collaboration efficiency and resource utilization.
Through multi-agent division of labor and collaboration, it supports end-to-end execution from coding to delivery, enhancing complex task processing capabilities and overall delivery quality.
Continuously accumulates project knowledge, task experience, and context memory during use, driving capability reuse, experience inheritance, and continuous optimization of results.
Flexibly defines expert roles, workflows, and capability boundaries according to your needs, creating an exclusive team of agent experts tailored to your own scenarios.
## How to use
Quest is built into Qoder IDE. Click the **Open Quest** button in the top right corner of the Editor to enter the Quest window.
Before you start a task, choose **Agent mode** or **Experts mode** based on the work you want to delegate:
- **Agent mode**: A single agent works autonomously to deliver tasks end-to-end.
- **Experts mode**: Multiple agents collaborate in parallel—best for full-stack development, technical research, and complex debugging.
When you use Quest together with **Knowledge**, the Agent understands your project better with every conversation—fewer repeated pitfalls, sharper answers, and lower Credit usage.
## Feature overview
Quest uses a three-column layout: the left column contains the task management area and extensions, the center is the conversation area, and the right is the function area.
### Task management area
The task management area is organized by **workspace**. After you open a workspace, you can create and manage Quests there, or open the same workspace in the **Editor** to keep coding. A workspace can contain multiple folders, making it easy to organize and manage content across directories within a single workspace. Quests in the workspace support **Pin**, **Fork**, rename, and delete. Each Quest shows a status: **Running**, **Action Required**, **Ready**, or **Error**.
For quick questions or tasks not tied to a specific project, you can start a conversation without binding to a project.
### My Quests board
My Quests is a global task board that aggregates all Quest tasks across workspaces, grouped by status, so you can quickly assess the state of your work. Click the board icon next to the Quests heading to enter.
- **Search bar**: A search box at the top lets you filter tasks by keyword
- **Workspace filter**: Tab-based filtering by workspace (e.g. All, or individual workspaces with task counts) to quickly narrow scope
- **Three-column kanban**: Tasks are automatically sorted into three status columns
- **Running** (blue): Tasks currently being executed
- **Waiting** (orange): Tasks awaiting user action (e.g. Action Required)
- **Completed** (green): Finished tasks
- **Task cards**: Each card shows the task name, description, workspace, and status badge — click to jump directly into the corresponding Quest conversation
### Extensions
A tools strip at the bottom of the left column provides global entry points Quest relies on—so you can reuse project knowledge, extensions, and preferences across tasks:
- **Knowledge hub**: Central place for knowledge Quest can use during runs, including auto-generated [Repo Wiki](../repo-wiki), [Knowledge Cards](../knowledge-engine/knowledge-cards) distilled from code and discussion, and [Memory](../knowledge-engine/memory) captured from conversations.
- **Plugin marketplace**: Browse and install official plugins to extend what Quest can do; installed plugins can be invoked by agents in tasks, see [Plugins](../../extensions/plugins).
- **Settings**: Open system and preference settings—account, models, shortcuts, proxy, appearance, and Quest-specific execution behavior.
### Conversation area
The conversation area is Quest’s main surface for dialogue, execution, and input:
- **Conversation flow**: Full transcript—your instructions, model replies, intermediate steps, and outputs.
- **Execution steps**: While a task runs, shows step-by-step progress, command output, and status, with rich content such as code blocks, logs, and file references.
- **Input box**: `@` references for files, folders, and symbols; model selection; microphone for voice input; context compression at the bottom.
- **Changes entry point**: After a run, a review entry appears above the thread; click it to open the **Review** panel on the right.
- **Quick conversation locator**: The Quest window adds a side-rail locator to jump quickly to a target part of the conversation.
### Function area
The function area expands and collapses from the side rail and includes:
- **Summary**: **Progress** for run status, **summary files** for the current Spec and code changes, and **references** to knowledge and tools used in the task (e.g. Repo Wiki, Memory, Skills, MCP), with clickable links.
- **Review and submit**
- **Diff view**: Detailed side-by-side diff for code changes.
- **Review and reject**: In **View changes**, inspect every modified file; reject per file or reject all.
- **Go to file**: Jump from a change to the corresponding source for a closer read.
- **Commit and push**: With a local Git repo, use **Commit**; when a remote is linked, **push** or open a PR.
See [Review and commit](./review-and-commit) for the full Diff view, review mode, and commit/push workflow.
- **Other panels**: Beyond summary and review, Quest surfaces built-in panels as needed for dev, debug, and backend work:
- **Terminal and file tree**: Workspace tree plus integrated terminal for structure and manual commands.
- **Browser**: In-IDE browser for previews or docs, see [Browser and Browser Agent](../chat/browser-agent).
- **Spec panel**: Shown when Spec-driven mode is on, see [Spec-driven mode](./spec-driven).
- **Supabase panel**: Connect and manage Supabase projects and preview schema, see [Supabase integration](./supabase).
## Tiled layout
Split the current view into multiple panes by dragging Quest tasks, so you can run and manage multiple tasks in parallel without constantly switching between tabs.
Tiled layout makes it easier to work on several tasks at once and compare outputs from different agents. You can expand a pane to focus on a single conversation, drag agents into different tile zones, and use keyboard shortcuts for quick navigation and arrangement. Your layout is preserved across sessions.
### How to use
Drag Quest tasks into different pane zones.
### Use cases
- Monitor multiple agents' progress simultaneously and compare outputs from different approaches
- Review code changes in one pane while continuing to iterate in another
- Reduce context-switching overhead when running several tasks in parallel
## Important notes
- **Cannot switch scenarios after start**: Please confirm your scenario selection before starting a task.
- **Editing messages triggers rollback**: Resubmitting an edited message rolls back workspace files to the state before the current conversation.
- **Mode selection sets execution strategy**: Agent and Experts modes are determined at task creation; subsequent conversations execute based on that mode's characteristics and cannot be switched.
# Agent Mode
Agent Mode is the autonomous programming capability within Quest. The Agent completes development tasks end-to-end — autonomously clarifying requirements, planning solutions, executing code, and verifying results, without continuous manual intervention.
## Use cases
- **Feature development and refactoring**: Ideal for developing new features, fixing tough bugs, or refactoring code. For tasks requiring clear technical plans, we recommend the Spec-driven scenario. The Agent will review the project context and generate a structured Spec document first, ensuring the overall direction aligns with your expectations before coding begins.
- **Rapid prototype validation**: Best for validating product ideas or building demo prototypes from scratch. Choose the Prototype exploration scenario to skip the Spec and jump straight into coding. You can see the actual running results immediately using the real-time preview capabilities in the Summary Files area.
- **Automated tool building**: Great for writing batch processing scripts, data cleaning tools, or custom CLI scripts. By choosing the Tool creation scenario, the Agent will automatically evaluate your environment and select the most appropriate tech stack to build the tool end-to-end.
- **Rapid iterative optimization**: Perfect for exploratory adjustments. You can let the Agent deliver a basic MVP version first, and after reviewing the initial results, continue to rapidly iterate by adding natural language requirements in the chat (e.g., "make the button larger" or "switch to a dark theme").
## User guide
### Create a task
Click the **New Quest** button at the top of the left task list, and select **Agent** mode in the popup panel. Here, you can specify your initial requirements and choose whether to enable Spec-driven execution.
### Edit sent messages
If you realize you missed crucial context or gave incorrect instructions during a conversation, you can click a sent message bubble to enter edit mode. In edit mode, you can:
- **Modify prompts**: Re-edit your input text to make it more precise.
- **Modify attached context**: Add, remove, or replace files, code snippets, and screenshots attached to the message.
- **Switch models and modes**: Switch to a more powerful model based on task difficulty or change the conversation mode.
After resubmitting your modifications, the workspace files will safely roll back to the state prior to that conversation turn. All file changes generated from that message onwards will be automatically discarded, allowing you to correct the course without any burden.
Context compression and one-click prompt optimization features are not supported in edit mode; manual adjustments are required.
### Revert
During the Agent's autonomous execution, if it takes a technical approach you don't like or you're unsatisfied with the code generated in the current turn, you can click the **Revert** button in the chat stream. The workspace will immediately be restored to the state before that turn's operations, and the reverted content can be viewed and compared in the Diff View. This gives you a perfectly safe space for trial and error.
Experts mode currently does not support Revert.
## Best practices
### Write good task descriptions
Avoid vague instructions like "fix the code." Clearly specify your specific goals, preferred tech stack, and acceptance criteria (e.g., "Write a React table component with pagination"). Use `@` to reference related files or code snippets, which greatly helps the Agent accurately understand the project context.
### Choose the right scenario and environment
- **By complexity**: For complex feature development involving multiple files, use Spec-driven mode to ensure a clear plan. For quick validations of small ideas, use Prototype exploration to skip the Spec.
- **Environment isolation**: For simple local tweaks, use the Local environment for quick feedback. For heavy development involving many files, we strongly recommend using the Worktree environment to fully isolate changes and keep your main branch safe.
### Utilize iteration effectively
Don't expect AI to deliver a perfect, complex system on the first try. Let the Agent complete an MVP version first, confirm the general direction, and then continuously add detailed requirements through multiple conversation turns. In Spec-driven mode, rely on conversation to let the Agent modify the Spec rather than editing it manually, ensuring the Agent maintains the best context understanding. The Agent supports unlimited iterations, allowing you to collaborate with it just like guiding a real engineer until you are completely satisfied.
# Experts Mode
Experts Mode is Qoder IDE's multi-agent collaboration feature designed for complex development tasks. Simply state your requirements, and the system automatically decomposes tasks, assembles an expert team, and executes design, implementation, testing, and quality assurance in parallel—delivering production-ready engineering results.
**In a nutshell**: You define the goal, the AI expert team delivers the result.
## Core Workflow

When you initiate a request, **Lead Agent** acts as the "brain" of the entire task—understanding goals, decomposing tasks, coordinating globally, ensuring quality, and dynamically pulling in experts from different domains to collaborate in parallel:
| Role | Responsibilities |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **Lead Agent** | Understand requirements, decompose tasks, coordinate scheduling, ensure quality |
| **Researcher** | Responsible for research analysis, code location, dependency mapping, environment inspection, and report generation |
| **Full-Stack Engineer** | Responsible for implementing and modifying frontend and backend code, as well as handling cross-stack and general coding tasks |
| **QA** | Responsible for running tests and builds, and collecting validation evidence |
| **Code Reviewer** | Responsible for reviewing code, identifying potential risks, and providing improvement recommendations |
| **UI Operator** | Responsible for browser and UI end-to-end validation, as well as visual bug reproduction |
| **Debug Engineer** | Responsible for reproducing failures, locating root causes, and diagnosing defects, with fix recommendations |
Lead Agent dynamically schedules expert sub-agents from different domains based on task needs. In the conversation flow, you can see the status of each expert agent and click to view details. Experts don't block each other and execute in parallel, while Lead Agent aligns and integrates results in real-time.
## Use Cases
Experts Mode is designed for medium-to-large engineering tasks—it delivers maximum value when you expect end-to-end, high-quality results. Here are three typical scenarios:
| Scenario | Example Task | How Experts Helps |
| --------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| **Full-Stack Development** | Develop user management module (registration, login, info management) | Lead Agent generates the plan, Full-Stack Engineer implements frontend and backend, QA tests in parallel, Code Reviewer ensures quality |
| **Complex Issue Diagnosis & Fix** | Production performance bottleneck involving multiple microservices | Lead Agent assembles Researcher and Full-Stack Engineer to analyze logs, trace call chains, and locate and fix the issue |
| **Technical Solution Research** | Evaluate GraphQL replacing RESTful API | Researcher gathers materials, Full-Stack Engineer assesses tech stack impact, deliver an actionable research report |
For simple, straightforward file modifications, Agent Mode remains the more efficient choice.
## User Guide
### 1. Switch to Experts Mode
In the configuration bar at the bottom of the Quest input area, click the mode switcher and select **Experts Mode**.
After switching, simply describe your requirements in natural language. Lead Agent will automatically understand the goal, create a plan, and coordinate the expert team to execute.
### 2. Requirement Planning
Experts Mode has built-in [planning capability](/user-guide/chat/plan-agent), generating an implementation plan before task execution:
1. **Describe requirements**: Clearly state goals, tech stack preferences, quality requirements, etc.
2. **Generate plan**: Lead Agent analyzes requirements and generates a structured implementation plan
3. **Review and adjust**: You can modify the plan before execution, adding missing steps
4. **Confirm execution**: After confirmation, the expert team begins parallel work
### 3. Task List
During task execution, a real-time task list appears at the bottom of the chat panel:
- **Pending**: Tasks waiting to be executed
- **In Progress**: Currently executing tasks
- **Completed**: Finished tasks
Click on any task to view its execution progress, process, and results at any time.
Additionally, when tasks require user confirmation or intervention, notifications will appear above the dialog for your timely attention.
In Experts Mode, Lead Agent will autonomously schedule and execute the vast majority of tasks, with only rare cases requiring your intervention:
- Terminal commands that hit the blocklist or are identified as high-risk operations
- Tool call count reaches the limit
- Other exceptional situations requiring manual intervention
### 4. Customize the Expert Team
Experts Mode lets you tailor the expert team to your needs: adjust how built-in experts behave, or bring in custom sub-agents to expand the lineup.
**Built-in Expert Team**
Personalize built-in experts so they fit your day-to-day workflow:
- **Model selection** — Each built-in expert defaults to following the user's model selection in Experts chat. You can override this to assign a specific model (e.g. Qwen3.7-Max, DeepSeek-V4-Pro) for individual experts, giving you fine-grained control over cost and capability trade-offs.
- **Additional Prompt** — Add extra prompts to built-in experts to guide or constrain their behavior in specific scenarios. Supports up to 10,000 characters.
- **Skills & MCP** — Add Skills and MCP servers to built-in experts to broaden what they can do.
Lead Agent does not support customization.
**Custom**
Create custom sub-agents for use in both Agent and Experts modes, invoked on demand by the lead agent. Supports model configuration, Skills, and MCP servers. See [Sub-agent Documentation](/extensions/subagent).
## Expert Team Canvas
Expert Team Canvas is a real-time visualization panel in Experts Mode that gives you a bird's-eye view of every expert's task progress and execution workflow in a single window. When the expert team is handling complex tasks in parallel, the canvas helps you stay on top of everything — which tasks are done, which are running, and what each expert is working on — without scrolling through conversation history.
### How to open
During task execution in Experts Mode, a task progress card appears at the top of the conversation area. Click an expert's avatar on the card to open the Expert Team Canvas.
### Layout
The canvas includes a task overview panel and a canvas view:
**Task overview panel**
The top section shows a task summary with counts of completed and in-progress tasks for a quick progress check. Below it lists all participating experts and their tasks, each marked with the current status (completed, in progress, pending). Click any expert's avatar to auto-scroll to their task area.
**Canvas view**
Displays each expert's task progress and workflow as cards laid out side by side. Each card corresponds to one expert's work, showing execution steps, output summaries, and current status — making it easy to see the full picture at a glance.
## Best Practices
### Help Experts Understand Your Intent Better
| Tip | Description |
| -------------------------------- | ---------------------------------------------------------------------------- |
| **Describe the end goal** | Clearly state what result you want, not just what operation to perform |
| **Provide context** | Relevant business background, existing code structure, technical constraints |
| **Specify quality requirements** | Whether tests, documentation, code standard checks are needed |
| **Indicate priorities** | Which are must-haves, which are nice-to-haves |
### Intervene Anytime Without Interruption
During expert team execution, you can intervene and adjust at any time without stopping the conversation:
- **Correct direction**: Notice something off track? Directly state what needs improvement, Lead Agent will adjust in real-time
- **Add requirements**: Have new ideas or missed something? Add anytime, the expert team will incrementally improve
- **Change priorities**: Requirements changed? Inform the new focus, the team will reallocate resources
## FAQ
1. Can I modify requirements during execution?
Yes. You can add information or adjust direction at any time. Lead Agent will coordinate the expert team to adapt to changes.
2. What about the cost and time for Experts Mode?
Experts Mode is suitable for medium-to-high complexity tasks. Compared to single Agent, it takes more time but delivers significantly better quality (internal testing shows \~67% quality improvement). For simple tasks, single Agent is more efficient.
3. How does the terminal tool work in Experts Mode?
In Experts Mode, the terminal tool automatically runs Terminal commands without requiring manual confirmation each time. Potentially dangerous commands are automatically executed in a sandboxed environment.
# Goal-driven
When you choose **Goal** mode in Quest, you only describe the outcome you want — Quest plans the path on its own, iterates continuously, and verifies the result. It's a good fit for tasks that take multiple steps and where you'd rather "have a result delivered" than direct each step yourself.
## Core capabilities
- You describe the goal; Quest breaks it down, plans the execution path, and keeps pushing forward without step-by-step instructions.
- After each round, Quest evaluates the current progress and judges whether the goal is met. If not, it automatically moves on to the next iteration.
- Pause, edit the goal, or delete the task at any time during a run. Pausing preserves the full context and intermediate artifacts.
- After you edit the goal, Quest continues against the new goal from the next round — it doesn't reset existing progress.
## Use cases
- **Long-running coding tasks**: work with clear success criteria and a verification loop — e.g. raising test coverage, performance tuning, cross-file consistency fixes. Quest autonomously iterates and verifies until the goal is met.
- **Large-scale refactoring**: code migrations, whole-repo framework upgrades, batch API replacements — tasks that can't be planned out step by step in advance. Describe the desired end state as a Goal, and Quest plans the path and keeps iterating.
## How to use
Click the "**+**" button on the input box and turn on the **Goal** toggle, or type `/goal` in the input box.
Describe the end state you want in natural language. A goal should describe the **expected result** rather than specific steps — Quest plans the execution path itself.
```
Example: `/goal raise the project's test coverage above 80%`
```
After you send the goal, Quest enters an autonomous execution loop:
```
- A Goal progress card appears above the input box, showing the current goal and run status.
- Quest evaluates progress after each round and continues automatically if the goal isn't met, ending on its own once the goal is reached.
```
The Goal progress card supports the following actions:
```
- **Edit**: click the edit button in the top-right corner of the card to change the goal description. Editing during a run takes effect after the current round ends; editing while paused takes effect immediately.
- **Pause and resume**: pausing preserves the full context and all intermediate artifacts; click resume to pick up from where it stopped.
- **Delete**: deletes the current goal task and returns the conversation to a normal chat state. Files and messages already generated are not deleted.
```
Goal-Driven Execution runs for up to **10 turns** by default and stops automatically once the limit is reached. You can raise the maximum turn budget from **Settings → Integrations → Built-in Capabilities → Goal-Driven Execution** to match the complexity of your task.
## Goal vs. Spec
| | Goal-driven | Spec-driven |
| --------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| **Positioning** | Goal-oriented; the Agent plans the path autonomously | Spec as the blueprint; implemented item by item per the plan |
| **Input** | Describe the desired end state | A structured solution description |
| **Execution** | The Agent iterates on its own and judges completeness | Executes the Spec task list in order |
| **Typical scenarios** | Raising test coverage, code refactoring, performance tuning | New feature development, building to a design, delivering well-defined requirements |
## Best practices
- **Describe a verifiable end state**: a good goal is "test coverage reaches 80%," not "write some tests." Quest needs a clear completion criterion to judge whether the goal is met.
- **Include key constraints**: if there's something you don't want changed, say so in the goal. For example, "optimize the internal implementation without modifying the public API."
- **Keep the scope reasonable**: an overly grand goal (such as "make the whole project better") makes it hard for Quest to stay focused. Breaking it into specific, measurable sub-goals works better.
- **Combine with scheduled tasks**: long-running Goal tasks are also well suited to running overnight. Use `/schedule` to set up a [scheduled task](./scheduled-tasks) trigger.
# Spec-driven development
In Quest, click the "**+**" button on the input box and turn on the **Spec** toggle (next to the **Goal** toggle) when you create a task to enable Spec-driven development: Quest aligns on scope, produces a structured **Spec**, lets you review it, then executes against it. This is the path for features that need traceable requirements and acceptance criteria.
## Workflow
After inputting your task, Quest may ask clarifying questions (in multiple-choice format):
- **Recommend**: Let Quest automatically select default answers
- **Continue**: Manually select and continue
- **Skip**: Skip questions and proceed with the conversation
Quest generates a structured Spec document:
- Requirement description
- Design plan
- Task breakdown
- Acceptance criteria
The Spec is displayed in the **Spec Tab** in the output area, with streaming output and download support.
- View the complete document in the **Spec Tab** on the right
- Modify Spec through **conversation** (can adjust anytime before clicking Build)
- You can also add **annotations** to specific parts of the Spec document and hand that feedback straight to the agent to adjust the Spec — no need to gather your comments into a separate message
- Click **Build** when satisfied to begin execution
- **To-do List**: Real-time task progress in the conversation area
- **Changed Files**: View code changes in the output area
- **Add requirements mid-task**: Send new requirements in the input box anytime — Quest adjusts the plan
After execution completes, review the run's code changes in the **Review** panel on the right, then stage and commit them — **Commit**, **Push**, or **Create New Branch** from the changes. See [Review and commit](./review-and-commit) for the full diff review, stage / discard, and commit / push flow.
## Convert a Spec into a scheduled task
After you finish requirement clarification and generate a Spec, you don't have to run it right away — instead of clicking **Build**, click the **Schedule** button on the Spec card, set the execution time, and save, and Quest will run that Spec automatically at the scheduled time. This is handy for moving time-consuming development work to off-peak overnight hours.
## Set a Spec as a Goal
After a Spec is generated, if you want Quest to iterate on it autonomously and keep pushing it forward, turn on the **Goal** toggle on the Spec card, then click **Build**. Once enabled, Quest runs that Spec in [Goal mode](./goal-driven) — evaluating progress at the end of each round and continuing to iterate until it's done, with no need to issue step-by-step commands.
# Scheduled tasks
In Quest, you can schedule a task to run automatically at a specified time using the `/schedule` command or a natural-language description.
## Use cases
- **Overnight code maintenance**: focus on feature work during the day and schedule time-consuming tasks such as refactoring, dead-code cleanup, and naming-convention fixes to run overnight.
- **Tests and documentation**: before you leave, schedule Quest to fill in test cases for the day's changes or generate module documentation, and review the results when you arrive the next morning.
- **Security and dependency scans**: schedule security-vulnerability scans and dependency checks regularly to keep the project's health up to date.
- **Combine with Goal mode**: schedule a [Goal](./goal-driven) task to run overnight so Quest can iterate autonomously toward the goal, making full use of off-peak hours.
## How to use
**Command trigger**: type `/schedule` followed by a task description in the input box, for example:
```
/schedule At 10 PM tonight, fill in tests for the code I changed today
```
**Natural-language trigger**: just include the timing intent in your message, for example "refactor the code I changed today tonight to improve readability." Once Quest recognizes the intent, it confirms any missing information and completes the creation.
After it's created, a scheduled-task card appears in the conversation flow. If you need to adjust it, click **Edit** on the card to open the form. When the scheduled time arrives, Quest starts the task automatically; the execution process and results appear in the corresponding conversation, where you can view them the next time you open it.
Make sure Qoder IDE is running at the scheduled execution time. If "Keep system awake" is enabled, Qoder IDE prevents the system from sleeping before the task time.
### Convert a Spec into a scheduled task
In [Spec-driven](./spec-driven) mode, after you finish requirement clarification and Spec generation as usual, click the **Schedule** button in the **build on** area of the Spec card, set the execution time, and save — Quest will then run that Spec automatically at the scheduled time.
### Edit the task form
Click the task card or the task entry in the **Summary** on the right to open the edit form, which includes the following fields:
- **Task name**: a short description of the task.
- **Scheduled time**: pick a date and time.
- **Task instructions**: the full prompt Quest uses when it runs.
- **Model selection**: defaults to the current conversation's model; you can switch it.
- **Goal toggle**: choose whether to run the task in Goal mode.
### Find and manage tasks
- **Clock icon in the left sidebar**: conversations with pending scheduled tasks show a clock marker in the conversation history list. The icon disappears automatically once all tasks have run or been deleted.
- **Summary panel on the right**: when a conversation contains scheduled tasks, a **Scheduled tasks** section appears in the Summary panel, listing all tasks; click one to jump to its edit form.
- **Multiple tasks per conversation**: you can create multiple scheduled tasks in the same conversation; they are managed independently and don't affect each other.
## Best practices
- **Write clear task instructions**: you won't be present when a scheduled task runs, so Quest relies entirely on the task instructions. Write them like a handover note for a colleague — make the scope, focus, and constraints explicit.
- **Make the most of Goal + scheduled tasks**: for goals that need continuous iteration, such as "raise test coverage to 80%," enabling Goal mode and scheduling it to run overnight works best.
# Review and commit
Whenever Qoder IDE makes code changes in Quest, you can review the full diff, decide what to keep or discard, and commit and push — all from the **Review** panel on the right.
## Review panel overview
The Review panel is divided into three areas:
- **Top toolbar**: scope switcher, global Stage All / Discard All actions, the commit button, and more.
- **File list**: the changed files within the current scope, with list / file-tree view toggle and search.
- **Diff view**: a line-level comparison for a single file, with per-file Stage / Discard actions.
## Switch the view scope
A single dropdown at the top of the panel lets you choose the scope:
| Option | Meaning |
| ------------------- | ---------------------------------------------------------------------------------------------------- |
| **Current Quest** | All changes accumulated in the current Quest |
| **Last Turn** | Changes from the most recent turn |
| **All Uncommitted** | All uncommitted changes in the workspace — every file with changes not yet committed in `git status` |
## Annotate code and diffs
If you spot something to adjust while reviewing, you can add annotations to specific parts of the code and diff views and hand that feedback straight to the agent. This helps it understand exactly what you want changed, without separately describing "which spot and how."
## Stage and discard
Once you've reviewed the diff, you can Stage / Unstage / Discard right in the panel.
Stage / Unstage require the current directory to be a Git repository.
**Global actions** (buttons at the top of the panel)
- `Stage All`: add every unstaged file in the current scope to the staging area.
- `Discard All`: discard all uncommitted changes in the current scope — requires a second confirmation and cannot be undone.
**Per-file actions** (buttons on the right of each file row)
- Unstaged files: show `Stage` and `Discard`.
- Staged files: show `Unstage` and `Discard`.
Actions take effect on click. Staging or discarding partial (hunk-level) changes within a file is not yet supported.
**External-change warning**: In the Current Quest / Last Turn scopes, if a file has other changes made outside this conversation, a yellow ⚠️ marker appears next to the file name.
## Commit and push
The Commit entry is available in every scope — you can commit the whole workspace from All Uncommitted, or commit from Current Quest / Last Turn to **commit only the files in the current scope**.
The top action bar has an action button with a dropdown. It defaults to **Commit** and can switch to:
- **Push**: push your local commits to the remote.
- **Create New Branch**: create a new branch from the current changes and commit to it.
Clicking Commit opens the commit dialog:
- You can manually control whether unstaged changes are included.
- The commit message can be written by hand or generated automatically.
# Terminal and Sandbox
The Agent executes shell commands directly in the terminal while performing tasks. Qoder IDE employs a tiered security model that automatically determines whether a command is executed directly, isolated in a sandbox, or paused awaiting your confirmation, based on the current execution mode and the command's risk level. The goal is to prevent accidental destructive operations while maintaining automation efficiency.
## Execution modes
Qoder IDE provides different execution modes tailored for various use cases, balancing automation efficiency with security protection.
### Agent Mode
- **Directly executed commands**: Routine development commands that do not fall into built-in risk categories (e.g., `npm install`, `git status`, `python test.py`) run automatically without intervention.
- **Commands requiring confirmation**: Commands that trigger potential risk categories or match your configured blocklist will pause execution and wait for you to approve or reject them in the IDE.
### Experts Mode
Experts Mode has a higher degree of automation.
- **Directly executed commands**: All commands not in the built-in risk categories execute directly, ignoring user-defined blocklists.
- **Sandboxed commands**: Potentially dangerous commands execute automatically in the sandbox without requiring your confirmation.
- **Permission escalation**: If a command fails in the sandbox due to restrictions, or if the model anticipates guaranteed failure in the sandbox, the AI will analyze the cause and may request a permission escalation. Qoder IDE will then pause and ask for your approval to execute the command in the terminal.
## Potentially dangerous commands
Commands involving categories such as file deletion, disk operations, permission management, and network configuration will be identified as potential risks by the system. In Agent Mode, these commands will pause and wait for your confirmation; in Experts Mode, these commands will automatically execute in the sandbox.
Additionally, the AI model independently assesses risk based on command semantics, even if a command is not in the above categories.
## Sandbox
The sandbox is an isolated execution environment used in Experts Mode. Potentially dangerous commands run inside it, ensuring they can only access the workspace directory and preventing accidental operations from affecting system files.
### Platform requirements
- **macOS**: Works out of the box with no extra configuration. Implements kernel-level isolation based on the native Seatbelt framework.
- **Windows**: Implemented via a proprietary sandbox engine distributed with the IDE. Supports Windows 7 and above. Runs directly in the native Windows terminal without requiring WSL or other dependencies.
- **Linux**: Requires bubblewrap (`bwrap`). Builds a lightweight isolated environment based on kernel user namespaces. On first use, if `bwrap` is missing, Qoder IDE will prompt and guide you through a one-click installation (auto-detecting `apt` / `dnf` / `yum` / `pacman` / `zypper`). If skipped, execution degrades to non-sandboxed mode with a warning.
### How the sandbox works
The sandbox allows workspace operations while preventing unauthorized access:
- **File System**: The workspace directory is writable, while other directories are read-only; sensitive paths like `~/.ssh` are invisible to sandboxed processes.
### Sandbox escalation workflow
In Experts Mode, the following may occur when a command runs in the sandbox:
1. The command executes in the sandbox and fails.
2. The AI analyzes the failure to determine if it was caused by sandbox restrictions.
3. If caused by sandbox limits, the AI requests a permission escalation.
4. Qoder IDE pauses and asks for your approval.
5. Once approved, the command executes directly in the terminal (without sandbox limits).
You can choose to cancel the command, letting the Agent try a different approach; or choose to execute it in the terminal, re-running the command without sandbox restrictions.
### Important notes
- **Domain-level Network Filtering**: Network control is currently a coarse on/off switch; granular domain-level filtering is planned.
- **Linux Container Environments**: When using Qoder IDE inside containers like Docker, sandbox isolation is limited to file system and network isolation.
- **Windows Sandbox is User-Mode**: Designed to prevent accidental writes and unintended outbound connections; it cannot fully mitigate adversarial attacks (e.g., if a process already has escalated privileges).
- **Shell Theme Compatibility**: Certain shell themes (e.g., Powerlevel9k/Powerlevel10k) may interfere with terminal output. If command output appears truncated or garbled, we recommend disabling the theme or switching to a simpler prompt while the Agent is running.
# Task Management
Quest provides flexible task management capabilities. This article explains how to create, pause, and resume tasks, as well as how to use features like Fork to efficiently manage your development workflow.
### Create a task
Click the **New Quest** button at the top of the left task list. You can configure the following when creating a task:
- **Mode selection**: Choose between Agent or Experts mode, which are suited for different scenarios.
- **Agent Mode**: End-to-end autonomous programming driven by a single agent. You describe the goal, and the Agent autonomously clarifies requirements, plans solutions, executes code, and verifies results. Suitable for feature development, prototype validation, tool building, etc.
- **Experts Mode**: Multi-agent collaboration where a Team Lead automatically breaks down the task and forms an expert team. Frontend, Backend, QA, and Code Review experts execute in parallel without waiting for each other; the Team Lead aligns and integrates results in real-time to deliver a viable engineering outcome. Suitable for full-stack development, complex issue diagnosis and repair, technical research, and other medium-to-large tasks.
- **Branch management**: Quest supports creating and switching Git branches for tasks, making it easy to isolate code changes.
- **Execution environment**: Local mode and Worktree mode. See the [Execution environments](./execution-environments) section below for details.
- **Spec-driven**: Choose whether to enable Spec-driven development. If enabled, the Agent will first generate a structured Spec document (requirement description, design plan, task breakdown, acceptance criteria) and wait for your confirmation before executing.
### Group, sort & filter
The top of the left **Quests** list provides view and filter controls that help you locate and switch between tasks quickly when you have many. Click the filter icon to open the customize menu:
- **Group by**: Group tasks by a dimension. Defaults to **Workspace**.
- **Sort by**: Adjust the task order. Defaults to **Updated**.
- **Filter by**: Filter which tasks are shown by **Status**, **Read**, and **Archive**; each defaults to **All**.
- **Reset**: Restore the default group, sort, and filter settings in one click.
### Pause and resume
During task execution, click the **Pause** button to pause. Once paused, click **Resume** to continue execution.
### Add requirements
During execution, send new requirements directly in the input box. Quest will adjust the plan and continue working.
### Task status management
The task lifecycle includes four states:
| Status | Description |
| :------------------ | :------------------------------------------------------ |
| **Running** | The Agent is currently executing |
| **Action Required** | Waiting for user confirmation or input |
| **Ready** | Task is complete, conversation can continue iteratively |
| **Error** | An error occurred during execution |
### Fork conversation
Click the more button on a session and select **Fork** to create an independent new session from the current one. The new session inherits the original session's complete context and message history, but subsequent conversations are independent and do not affect each other.
Ideal for trying different solutions based on the same discussion or splitting a task into multiple independent parallel threads. In Quest tasks, you can also Fork from any conversation turn to create a new task branch and continue from there.
Fork is also available in the Editor view once a session finishes — the flow is identical.
# Execution Environments
Quest supports execution environments such as Local and Worktree. This article introduces the use cases and configuration for different environments, helping you safely and efficiently isolate and execute tasks.
| Environment | Behavior | Best for |
| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------- |
| **Local** | Work directly in your open workspace; edits land in the project you have open | Quick tasks, fast validation |
| **Worktree** | A separate [Git worktree](https://git-scm.com/docs/git-worktree) checkout so changes stay isolated from your main branch until you apply or merge | Medium complexity, many apply iterations, parallel tasks in one repo |
Quest supports parallel tasks across environments where your plan allows.
## Worktree
Worktree mode uses a separate Git worktree checkout in the background so the Agent can execute tasks in an isolated environment. Your main workspace stays clean, and multiple worktrees can run in parallel.
### When to Use
| Scenario | Description |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Parallel Tasks** | Handle multiple requirements or refactoring efforts at the same time, advancing each track independently without interference |
| **High-risk Refactoring** | Let the Agent boldly attempt architecture changes or large-scale renames; if you're not happy, discard the result and your main workspace is untouched |
### How to Use
#### Create a Worktree
1. In the run-environment area at the top of the chat panel, click the current mode (e.g., "Local")
2. Choose **Worktree** from the dropdown
3. In the branch dropdown next to the mode selector, choose which local branch the Agent should base the worktree on
4. Enter a task and send it. The Agent runs the work in a separate worktree.
If your main workspace has uncommitted changes, the panel shows an **Include uncommitted changes** toggle. When enabled, those changes are synced into the worktree at creation time so the Agent sees your latest code.
#### Move to Local
When the Agent finishes work in the worktree, you can bring the results back to your main workspace to continue development:
In the task list on the left, find the corresponding worktree session and click **Move to local** on that session. This moves the worktree's branch state and uncommitted changes back to your main local workspace, so you can continue the work locally.
Before you move to local, your local workspace must be clean (no uncommitted changes). Commit or stash your current changes first.
#### Review & Commit
If you don't need to bring the changes back locally, you can commit directly from the worktree: open the **Changes** panel on the right of the session to review all file changes the Agent made. Once everything looks good, create a new branch and commit the code from the panel.
### Startup Script
If you need to run initialization steps automatically when a Worktree is created (such as installing dependencies or copying environment variable files), go to Settings and find **Worktree configuration for local tasks** to edit the startup script.
### Cleanup
#### Automatic Cleanup
The system automatically cleans up older worktrees to free up disk space. You can configure the cleanup policy at the bottom of the management panel:
- **Maximum retained**: Each workspace retains 15 worktrees by default.
#### Manual Cleanup
- In the session list on the left, **Delete** a worktree session to remove the corresponding worktree along with it.
- You can also manage and delete worktrees you no longer need from Settings.
### Notes
- **Requires a Git repository**: The project must be a Git repository for the Worktree option to appear.
- **Keep the workspace clean before handoff**: When you move to local, your local workspace must have no uncommitted changes.
- **Disk usage**: Each worktree is a separate file checkout. For large projects, multiple worktrees can consume significant disk space. Set a sensible maximum retained count to avoid running out of space.
# Supabase Integration
[Supabase](https://supabase.com/) is an open-source Firebase alternative that provides PostgreSQL databases, user authentication, file storage, and real-time data sync. Quest supports authorizing and connecting to Supabase projects directly, so you can handle frontend development and backend data management within the IDE — no switching between browser and editor.
You can connect multiple Supabase projects simultaneously and preview database table schemas (Schema) directly in the IDE to stay on top of your backend data model.
**Core features:**
- **Multi-project connections**: Authorize and connect to multiple Supabase projects for quick switching between environments (development, testing, production) or different services.
- **Database schema preview**: View database table structures of connected projects directly in the IDE — including table names, fields, types, and relationships — without opening the Supabase Dashboard.
- **Enhanced database capabilities**: AI agents are aware of your database structure and can automatically generate table creation statements, data schemas, and query logic based on task requirements, ensuring frontend-backend data model consistency.
- **One-click authorization**: Securely connect to Supabase through the OAuth flow — no need to manually configure API Keys or connection strings.
**Supported Supabase services:**
After connecting a Supabase project, you can use the following services in Quest:
- **Database (PostgreSQL)** — Full SQL support for storing and querying application data. AI can automatically generate the tables and data schemas you need. See [Supabase Database docs](https://supabase.com/docs/guides/database/overview).
- **Authentication** — Securely manage user registration, login, and access control. Supports multiple auth methods including email/password and OAuth providers like Google and GitHub. See [Supabase Auth docs](https://supabase.com/docs/guides/auth).
- **Storage** — Upload and manage images and other files through Supabase Storage, suitable for user avatars, file uploads, and static media resources. See [Supabase Storage docs](https://supabase.com/docs/guides/storage).
- **Realtime** — Push data changes to your application in real time, supporting live chat, dynamic feeds, collaborative dashboards, and more. See [Supabase Realtime docs](https://supabase.com/docs/guides/realtime).
**How to use:**
When building a project in Quest, if the AI determines a Supabase connection is needed, it will prompt you in the chat panel. You can also connect proactively:
Go to [Supabase](https://supabase.com/) to register an account and create an organization and project.
In Quest, click the **Supabase** tab at the top of the tool panel. Click the **Authorize** button, follow the prompts to complete the OAuth flow, select your Supabase organization, and confirm.
After authorization, the panel displays your organizations and projects. Find the target project and click **Connect** to link it to the current Quest project.
Once connected, you can preview database table schemas directly in the Supabase panel, and the AI will use this schema information to assist your development.
Qoder IDE projects can only connect to active Supabase projects. To switch organizations, click the toggle button next to the organization name.
**Use cases:**
- **Full-stack app rapid scaffolding**: Describe your application requirements in Quest, and the AI automatically generates the frontend UI and configures the Supabase backend — including database tables, authentication flows, and storage strategies.
- **Data model design and validation**: Use the in-IDE schema preview to check whether AI-generated data models meet your expectations in real time, and adjust before continuing development.
- **Multi-environment management**: Connect to both development and production Supabase projects simultaneously to easily view and compare data structures across environments.
AI-generated database operations (such as creating tables or modifying schemas) take effect directly on the connected Supabase project. For production environments, confirm operations carefully before executing.
- **Authorization security**: The authorization process uses OAuth — Qoder IDE does not store your Supabase password. Authorize only the organizations and projects you need, following the principle of least privilege.
- **Network dependency**: Supabase integration requires a network connection to access Supabase cloud services. Ensure your network environment is working properly.
# Qoder Voice
Qoder Voice is a realtime voice companion built into Qoder IDE. Speak your ideas the way you would in a voice chat: explore directions, shape a plan, and drive tasks, software, and your computer forward through conversation alone. The voice layer handles the dialogue and the judgment calls, while the actual inspecting, editing, and executing is carried out by a backend Agent on the same task timeline — so everything stays audible, visible, and reviewable.
Qoder Voice runs in the Quest window. The Chat panel in the editor window does not offer realtime voice.
## Starting and ending a session
- **Three entry points**: the voice button on the Quest home page, **Start voice** at the bottom of a voice task, and a customizable shortcut (which also works when the app is not focused).
- **Speaking creates the task**: starting a session automatically creates a voice task that inherits the workspace selected under **Start in** on the home page (local / SSH / WSL / Dev Container), so the task lands in the matching workspace group. Only an explicit "no workspace" choice sends it to Chats.
- **Nothing is lost while connecting**: the input box keeps its usual appearance but is temporarily read-only. Whatever you say during this window is buffered and delivered in order once the connection is ready.
- **Three ways to end**: the close button on the orb's control bar, Stop at the bottom of the task, or simply saying "end the call." Ending voice does not stop backend work that is already running; when voice and a task are running at the same time, the first click stops only voice and the second stops the task.
## The floating orb
The orb is a standalone transparent window rather than something embedded in the IDE, so it can float above any application and follow every ordinary desktop space.
- **Readable state**: connecting, listening, you speaking, AI speaking, thinking, silent, error, and closing — eight states in total. The voiceprint motion comes from your real microphone envelope, and the AI-speaking state follows the actual playback queue.
- **Three looks**: Classic Voiceprint (default), Breathing Orb, and Capsule. Right-click to switch; the choice is remembered per machine.
- **Anchored or free**: by default the orb sits above the input box of the current voice task. Drag it more than 4px and it becomes free-floating; the position is preserved when you switch tasks, windows, or apps and come back. It re-anchors when you reopen its task or click the orb.
- **Hover control bar**: mute playback, turn off the microphone, and end voice. Muting only silences playback — the microphone keeps capturing. Turning off the microphone means "I'm done talking": trailing silence is appended before capture is released.
- **One click returns to the scene**: clicking the orb immediately brings Quest to the front and opens the voice task it belongs to, without changing capture or mute state.
- **Captions while muted**: while muted, the current AI reply is shown as live captions above the orb (up to three lines), and a label in the upper right shows **Connecting / Working / Thinking**.
## Moving work forward like a chat
- **Speaking is the task**: small talk, or anything the current context already answers, gets a direct spoken reply. When code needs to be read, information looked up, commands run, or Quest tasks operated, the voice layer hands one complete request to the backend Agent. A separate Quest task is created only when you explicitly ask for independent, persistent background work.
- **Transcript and execution are layered**: your transcript and the AI's flow into the conversation in realtime and look just like ordinary messages. Tool calls, thinking, and execution reports are collapsed by default in the **Worked** section — expand it for the details.
- **Interrupt any time**: the moment you start speaking, playback stops. Ordinary follow-ups are queued behind the current work and you are told plainly that they are queued; only a clear change of direction or an explicit "stop right now" interrupts the current turn before the new goal is executed. Work that is queued but not yet started can be cancelled by a newer request.
- **Only meaningful updates**: task results are one or two spoken sentences by default. When you explicitly ask for research, investigation, or a comparison, you get a multi-sentence summary covering the conclusion and the key findings. When background work has nothing substantial to report, it stays quiet instead of narrating waiting.
- **When approval is needed**: a confirmation card appears at the bottom, and voice gives one neutral reminder to approve or reject it — without reading out sensitive tool details.
- **Typing still works**: while voice is live, plain text input goes into the voice session; input with attachments or a slash command is still sent as an ordinary follow-up.
## Screen context (Appshot, macOS only)
When you say "this," "this page," or "my screen," Qoder IDE can read the image and text of the foreground app window as context. The first time it is needed, macOS asks for Accessibility and Screen Recording permission.
The toggle is on by default and can be turned off in voice settings at any time. Once off, voice explicitly declines screen access and no screenshot is written into the session (a hard gate, not just a prompt instruction); on non-macOS platforms it is always treated as off. Ordinary non-voice tasks are unaffected by this setting.
## Settings
Under **Settings → Voice → Realtime voice** in the Quest window:
- **Shortcut**: edit the key binding that starts realtime voice. It is released automatically when the entry point is unavailable, so it never keeps occupying a binding other apps may need.
- **Voice**: Anna / Lily. A running connection is never switched mid-session; the change applies to the next connection.
- **Speaking speed**: Slow / Normal / Fast, applied immediately. It changes only the delivery pace, never the content or the language.
- **Voiceprint Recognition** (off by default): records about 10 seconds of 16 kHz mono audio so your voice is recognized first in noisy or multi-speaker environments. You must explicitly confirm how it is stored before enabling it; turning it off only stops using the voiceprint and does not delete it. You can re-record over it or delete it at any time.
- **Appshot**: see the previous section.
## History and recovery
- Voice transcripts and execution history are both persisted and restored as-is when you reopen the task; completion announcements that never reached you in an earlier connection are not replayed.
- Reopening a task establishes a new voice connection but keeps the same voice history.
- A task forked from a voice task is an ordinary Agent Quest and inherits neither the voice session nor voice-specific capabilities.
## Notes
- **Window scope**: realtime voice is available only in the Quest window, and its settings are shown only there.
- **A single connection**: the whole application allows only one realtime voice connection at a time. A new connection replaces the old one, and the previous window closes out normally as "connection replaced."
- **Startup failures are reported once**: a denied microphone, no device, a device held by another app, an unsupported environment, or insufficient quota each produce the matching message and return you to the page you were on, leaving no half-open voice state behind.
- **No automatic reconnect**: after a drop or timeout, no pending-reconnect state is kept — start voice again from the bottom of the task.
- **Full duplex throughout**: echo cancellation removes only the model's own speech, and the microphone is never closed during playback, so you can interject at any time.
- **Linux**: native Wayland sessions do not support global pointer queries or programmatic window movement, so orb interaction is limited there.
# Overview
Knowledge is a core capability of Qoder IDE that automatically accumulates and manages the business knowledge generated during your daily development. It enables the Agent to understand your project better with each conversation—reducing repeated mistakes, improving answer accuracy, and lowering Credit consumption.
Knowledge includes three types of knowledge sources:
- [**Repo Wiki**](../repo-wiki): Structured documentation automatically generated based on the codebase, covering project architecture, module relationships, and implementation details.
- [**Knowledge Card**](./knowledge-cards): High-density knowledge units extracted from code, including architecture documents, code specifications (Spec), and tech stack information.
- [**Conversation Memory (Memory)**](./memory): Pitfalls, decision rationales, and project experience automatically extracted from each conversation, persistently accumulated as reusable knowledge.
These three types of knowledge flow into the same engine, requiring no manual organization, and the Agent will automatically invoke them when needed.
**Two paths for automatic knowledge accumulation:**
- **Code side**: When generating the Repo Wiki, the system automatically extracts code intent, design plans, and contextual discussions into Knowledge Card content;
- **Conversation side**: Pitfalls, decision rationales, and project experience during interactions with the Agent are automatically extracted into Memory knowledge.
# Repo Wiki
Repo Wiki automatically generates structured documentation for your project and continuously tracks changes in code and documentation.
When you query knowledge points, code explanations, or add feature enhancements during development, Repo Wiki deeply analyzes the project structure and code implementation. Combining Repo Wiki with context information, it provides more accurate and detailed answers and documentation support, giving the agent a deeper understanding of the codebase.

## Use Cases
- **Architecture and Implementation Queries**\
Relying on pre-built architectural knowledge, the agent can quickly answer questions like "How is X implemented?" or "Which services depend on this module?" with almost no need to invoke tools.
- **Agent-Driven Development Tasks**\
When context width is limited, Repo Wiki accelerates code location, supporting tasks such as:
- Adding new features
- Fixing bugs
## Repo Wiki Generation
The Wiki in your repository is not static—it stays synchronized with your code.
The Wiki updates in three key scenarios. Understanding when and why it triggers helps you keep the Wiki updated in real-time.
1. **Initial Wiki Generation**
When you open a project for the first time, no Wiki exists by default. You can generate it from scratch with one click.
2. **Code Changes Detected**
After the initial generation, the system continuously monitors code changes.
If you modify content already recorded by the Wiki (e.g., function signatures, class definitions, API endpoints), the system detects the inconsistency between the current code and the existing Wiki. You can click **Update** to regenerate only the affected parts.
3. **Git Directory Sync**
If you directly edit Markdown files in the Git directory, the system detects inconsistencies between the Git content and the Wiki. You can click **Sync** to synchronize the Git changes and update the Wiki.
4. **Generation Limits**
- A maximum of 10,000 files per project. If your project contains more than 10,000 files, it is recommended to exclude non-essential paths in Qoder IDE Settings → Codebase Indexing → Index Exclusions.
- Only supports Git repositories with at least one commit.
## Intervening in Wiki Generation
Repo Wiki is not a "generate once and read-only" artifact. You can guide the direction through a configuration file before generation, or modify it anytime after generation. Every knowledge revision made by the team is recognized by the system as new cognitive deposits—it won't be overwritten by the next automatic update, but instead reverse-synced to the corresponding knowledge cards—truly embedding human judgment into knowledge assets.
### /knowledge Command
Type `/knowledge` in the chat input to intervene in Repo Wiki and Knowledge Cards:
| Operation | Description |
| -------------- | ------------------------------------------------------------------- |
| **Generate** | Generate Wiki or Knowledge Cards for the project for the first time |
| **Modify** | Make partial modifications to existing knowledge content |
| **Supplement** | Append new content to existing knowledge |
| **Rewrite** | Completely rewrite a knowledge page or card |
**How to use:**
1. Invoke `/knowledge` in the input box
2. Enter your instruction describing the desired changes
3. Optionally upload local files as reference (e.g., design docs, API docs)
4. The Agent will modify the corresponding knowledge content based on your instruction
Manually modified content is marked and protected by the system—it won't be overwritten during the next automatic update, making every team knowledge revision a persistent knowledge asset.
### wiki\_plan.yaml — Pre-Generation Configuration
Through a configuration file, you can inject guiding intent before Wiki generation to control direction and scope.
Type `/knowledge-plan` in the chat input to create or edit the `wiki_plan.yaml` pre-generation configuration file, controlling the generation strategy for Wiki and Knowledge Cards.

**File location:**
```text
/.qoder/repowiki/wiki_plan.yaml
```
This file is shared with the team via Git commits.
**Configuration structure:**
```yaml
version: 1
repowiki:
template: "" # Preset template (architecture / product_requirement)
notes: # Inject guidance prompts during the planning phase
- text: "Prompt text"
author: "Author"
documents: # Page allowlist (strictly outputs listed pages when provided)
- title: "Page title"
goal: "Writing intent for this page"
parent: "" # Optional, parent page title
hints: "" # Optional, additional writing hints
knowledgecard:
notes: # Inject guidance prompts for knowledge card planning
- text: "Prompt text"
scope:
include: [] # File allowlist (.gitignore syntax)
exclude: [] # File blocklist (.gitignore syntax)
```
**Key configuration options:**
| Option | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `repowiki.template` | Preset template: `architecture` (comprehensive technical analysis) or `product_requirement` (product requirements format output) |
| `repowiki.notes` | Guidance prompts injected during planning to direct AI focus |
| `repowiki.documents` | Page allowlist; when provided, pages are strictly generated per the list |
| `knowledgecard.notes` | Knowledge card guidance prompts, influencing module partitioning |
| `scope.include / exclude` | Controls which files are visible during generation |
**Example:**
```yaml
version: 1
repowiki:
notes:
- text: "Documentation should focus on business workflows rather than code details, targeting new engineers"
documents:
- title: "System Architecture Overview"
goal: "Describe overall system architecture, core modules and their interactions"
- title: "Order System"
goal: "Explain the full order lifecycle"
parent: "System Architecture Overview"
knowledgecard:
notes:
- text: "Focus on modeling the payment and order core subsystems"
scope:
include:
- "src/**"
exclude:
- "**/test/**"
```
After modifying `wiki_plan.yaml`, you need to manually trigger "Generate" or "Regenerate" for changes to take effect.
## Repo Wiki Sharing
Supports Wiki sharing to facilitate more efficient knowledge flow within the team.
Once a team administrator enables the **Knowledge** toggle in the Web console, any Repo Wiki generated by a team member is automatically synced to the team. Other members simply open the same repository branch and click **Generate** to automatically retrieve the team's latest knowledge—no manual pulling required. Any changes to the project's knowledge by team members are synced to everyone, ensuring the team's knowledge stays consistent and up-to-date.
Automatic team sharing is only available in the Teams plan. Alternatively, you can manage knowledge via Git sync.
When generating a Wiki locally, the system automatically creates a dedicated directory in your code repository: `.qoder/repowiki`.

You can commit and push this directory to a remote branch. Team members can then pull the generated Wiki content via `git pull`—no extra configuration required.
## Multilingual Support
The Wiki system supports **multiple languages**—you can select your preferred language when generating the Wiki. Currently, **English** and **Chinese** are supported.
When generating the Wiki, the system automatically creates independent directories for each selected language under the Git directory based on your language choices (e.g., `repowiki/zh/`, `repowiki/en/`).
## Billing
Generating and updating the Repo Wiki consumes Credits as usual. You can check the consumption records in [Usage - Credits](https://qoder.com/account/usage).
# Knowledge Card
Generated synchronously with the Repo Wiki, a **Knowledge Card** is a high-density knowledge unit extracted from code. It stores architecture documents, code specifications (Spec), and tech stack information in a format that the Agent can easily consume directly. It continuously tracks code changes during every commit, maintaining real-time accuracy and relevance.

## Use Cases
- **Architecture Document-Driven System Understanding**: Based on pre-built architecture documents, the Agent can quickly answer questions like "What is the overall design concept of this module?" or "What are the dependencies between these services?" without repeatedly searching the codebase.
- **Code Specification (Spec)-Guided Development Tasks**: When you need to ensure code style, interface design, or business logic complies with team standards, the Agent can refer directly to the specification knowledge, supporting scenarios like:
- Automatically aligning with naming conventions and interface agreements when adding features
- Quickly verifying if implementations meet spec requirements during code review
- Identifying potential risks that violate specs when fixing bugs
- **Tech Stack Knowledge Accelerating Technical Decisions**: Combining pre-configured tech stack information, the Agent efficiently supports the following tasks in context-limited or cross-language/framework scenarios:
- Evaluating compatibility when introducing new dependencies
- Generating code snippets that conform to the current tech stack style
- Answering technical environment questions like "Which frameworks and versions are used in the current project?"
## Knowledge Card Types
- **Architecture Documents**
Records the overall design concepts of modules, service dependencies, and key decisions, helping the Agent understand the complete system without reading code line-by-line.
- **Code Specifications (Spec)**
Accumulates team coding standards, naming conventions, interface agreements, and business logic constraints, ensuring the Agent automatically aligns with team standards when generating code.
- **Tech Stack**
Records frameworks, libraries, and version information used in the project, helping the Agent make decisions that match the current technical environment when introducing new dependencies or generating code snippets.
## Knowledge Card Generation
It is recommended to select the main branch and core development branches for generation to cover the core content of the project. During generation, completed cards can be previewed in real-time without waiting for the entire process to finish.
**Generation Recommendation**: Prioritize **Knowledge Card** generation on the main branch (`main` / `master`) and frequently used team development branches to ensure the Agent understands the most critical business logic and code structures.
## Editing Generated Knowledge
After Knowledge Cards are generated, you can manually modify existing knowledge by invoking the `/knowledge` command in the input box. Simply type your instructions describing the desired changes, or upload local files as reference material, to update the content of your Knowledge Cards.

## Sharing and Multilingual Knowledge
**Knowledge Card** sharing helps knowledge flow more efficiently within your team.
Once a team administrator enables the **Knowledge** toggle in the Web console, any Knowledge Cards generated by a team member are automatically synced to the team. Other members simply open the same repository branch and click **Generate** to automatically retrieve the team's latest knowledge—no manual pulling required. Any changes to the project's knowledge by team members are synced to everyone, ensuring the team's knowledge stays consistent and up-to-date.
Automatic team sharing is only available in the Teams plan. Alternatively, you can manage knowledge via Git sync.
When you generate **Knowledge Card** locally, the system automatically saves the data to a dedicated directory in your code repository: `.qoder/repowiki`. You can commit and push this directory to a remote branch. Team members can then pull the generated Knowledge Card content via `git pull`—no extra configuration required.
Additionally, **Knowledge Card** supports **multiple languages**. You can select your preferred language when generating them (currently supporting **English** and **Chinese**). Based on your language choices, the system automatically creates independent subdirectories for each selected language (e.g., `zh/`, `en/`).
## Billing
**Knowledge Card** generation and updates consume Credits as usual. You can check the consumption records in [Usage - Credits](https://qoder.com/account/usage).
# Memory
Qoder IDE offers long-term memory capabilities. As developers interact with Qoder IDE, it gradually builds a comprehensive memory base that includes information about the individual developer, specific projects, and encountered issues. This memory is automatically organized and updated over time.
With this capability, Qoder IDE can engage with developers more effectively and, over time, develop a deeper understanding of each developer's unique needs and context.
## **Active memory**
Switch to Agent Mode in the Chat panel and type what you'd like Qoder IDE to remember. Qoder IDE will save the information. You can retrieve it later by asking in the Chat panel.
## **View memories**
Click **Knowledge Center** in the bottom bar or left navigation to enter the **Memory** panel and view saved memories. Here you can:
- **Search and filter**: Support searching memories and filtering by maturity, category, and project.
- **Manage memories**: You can edit or remove unwanted entries. Alternatively, you can also view them in Editor's **Qoder IDE Settings** > **Memories**.
## **Memory scope**
When a developer works on a project, both global memories—reflecting personal preferences—and project-specific memories are activated and applied throughout all interactions with Qoder IDE.
# Security
> Qoder Security embeds security into your dev workflow — three-tier progressive scanning and one-click fixes, keeping every line secure before commit.
AI has multiplied how fast developers write code — and how fast attackers find and exploit vulnerabilities. Traditional scanners fire late in the pipeline, drown developers in false positives, and can't explain themselves. **Qoder Security shifts detection and remediation to the moment you write each line.** Every finding comes with a fix suggestion; Qoder's main Agent applies the fix, and you review the final diff.
## Core capabilities
- **LLM-driven:** Instead of matching regex patterns, the model reads code semantics — it can tell whether a value is attacker-controlled, whether a call actually reaches a sink, and whether a team's own utility method really neutralizes the risk.
- **Multi-Agent cross-verification:** Findings are challenged and confirmed by multiple Agents from different angles before you see them, which cuts false positives and stabilizes recall.
- **Layered by design:** Fast checks run in the coding loop. Semantic diff scans run at the end of a task. Cross-file data-flow analysis runs before you push. A repo-wide audit is one command away.
## How the tiers work together
Security and speed usually pull against each other: deep scans are slow, fast scans are shallow. The layered design pairs each strength with the right moment — **fast when it should be fast, deep when it should be deep**.
| Tier | Target | Depth | When it runs |
| --------------------- | ------------------------------------------------------------------------ | ----------------------------- | --------------------------------------- |
| Static Check (L1) | Code generated in the current task | Pattern match, near-zero cost | Automatically during coding |
| Lightweight Scan (L2) | Incremental code | Semantic, diff-scoped | Recommended at the end of a coding task |
| Deep Scan (L3) | Incremental code, tracing complete data flows across files and functions | Cross-file data-flow | Recommended before push |
From inline checks in the coding loop, to per-diff review, to pre-push deep audits, to on-demand repo-wide scans — security becomes a default that lives inside every keystroke and every commit.
## Turn on Code Security
1. Open Qoder and go to **Settings**.
2. Pick **Security** from the sidebar.
3. Under **Scanning Tiers**, confirm the toggles for **Static Check (L1)**, **Lightweight Scan (L2)**, and **Deep Scan (L3)**.
## Credits estimates
L2 and L3 consume Credits — scans are blocked when your Credits run out. L1 Static Check is free. See [Credits](/Credits) for details.
Rough consumption (based on internal testing; actual usage depends on code complexity, number of vulnerabilities, and other factors):
- **Lightweight Scan (L2)**: \~5 Qoder Credits per 500 lines
- **Deep Scan (L3)**: \~20 Qoder Credits per 500 lines
## Scanning tiers
### Static Check (L1)
**For code generated in the current task.** Based on high-risk pattern matching, it instantly detects common risks like dangerous function calls and auto-applies the fix.
- **When it runs**: automatically, right after every code-writing step in the session. No manual trigger, no confirmation needed.
- **How you see it**: findings are surfaced inline in the current chat. Results feed straight back into the session context and the model handles them in the next revision.
- **Use it for**: the everyday AI-generated-code loop, where a model may quietly reach for `eval()` or paste a real API key into a config. L1 is the always-on baseline that keeps obvious risks from landing in the file.
### Lightweight Scan (L2)
**For incremental code.** Deeply understands code semantics to precisely identify risks such as SQL injection, remote command execution, and sensitive-data leaks.
- **When it runs**: recommended when a single coding task is close to wrapping up — Qoder surfaces a recommendation card in the chat at the right moment:
> **Scan your code for hidden risks**
Clicking auto-fills:
```
/security-scan Run a lightweight scan for me
```
You can also type this yourself, or ask in plain language ("run a lightweight scan", "check my changes for risks"). Ignore the card if you don't want to scan — the rest of the flow is unaffected.
- **How it works**: say you just spliced a request parameter straight into a system command. L2 simultaneously reasons about "this parameter is attacker-controlled" and "this call really executes a command," and flags command injection. Regex-based scanners cannot bridge those two facts.
- **How you see it**: risk location, description, and a suggested fix appear inline in the chat, with a Review panel diff on the right.
- **Use it for**: catching finish-line risks in a diff — the SQL string you just concatenated, the request parameter you piped into a shell, the API key that slipped into a config value.
### Deep Scan (L3)
**For incremental code, tracing complete data flows across files and functions.** Uncovers hidden linked vulnerabilities invisible from a single-file view, for more comprehensive analysis.
- **When it runs**: typically recommended by the model before commit / push. When it detects a push intent in the session, it may surface an **Ask Question** card asking whether to run a security scan first. If your intent to scan is already explicit, the scan runs directly.
- **Other entry points**: in the Quest window, the Commit dropdown has a **Scan & Push** entry when L3 is on — clicking auto-fills `/security-scan Run a deep scan and push`.
- **How it works**: an external parameter flows across files into a SQL concatenation, passing a team-authored sanitizer function along the way. L3 actually reads the method's implementation: it sees the method only strips single quotes, notices the parameter is being spliced into an `order by` clause where single-quote filtering doesn't help, and concludes injection is still possible.
- **How you see it**: results are shown inline in the chat flow — the exact form is model-decided, but typically covers severity, location, description, and a suggested fix. When it fits, an Ask Question card follows so you can hand the remediation to the Agent or skip.
- **Use it for**: the last checkpoint before your code leaves your machine. L3 excels at the "safe when viewed alone, unsafe when connected" class — SQL injection chains passing through custom sanitizer functions, path traversals that traverse decoding boundaries, taint that only becomes exploitable after crossing several files.
## Full Scan
**For repository-wide audits.** Chain two slash commands in the chat — `/security-scan` to run the scan, then `/canvas` to render the results as a visual report:
```
/security-scan run full scan and /canvas generate a visual security report
```
Full Scan runs on the whole repository — both wall time and Credits usage can be significant. A single `/security-scan` invocation is capped at 10,000 lines of code; if your repo is larger, split by directory or by commit range.
Qoder walks the repository and generates a **Visual Security Scan Report** as a Canvas artifact — open it from the chat like any other Quest output.
A typical report may include a scan status header (target, completion time, remediation state), a Findings summary table (Severity / Title / CWE·OWASP / Location), and per-finding details with affected code and remediation guidance.
## Manual scans
You can also start a scan yourself at any time — narrower than a Full Scan.
- **Slash command**: type `/security-scan` in the chat and describe what you want. Examples:
```
/security-scan Run a lightweight scan for me
/security-scan Run a deep scan and push
/security-scan Scan the src/api directory
/security-scan Scan the last 3 commits
```
- **Natural language**: "scan my code", "check for security risks", "run a deep scan", "scan the `mydir` folder" — the Agent maps these to the right scope and tier.
# Better Harness
> An agent that reviews your project's Harness Engineering and points out where the gaps are — and can start a fix task for you with one click.
## What is Agent Harness
Today's Coding Agents can read requirements, modify code, run tests, and even submit Pull Requests. But "can do a lot" doesn't mean "does it well." An Agent typically cycles through "understand the task — take action — check results — adjust" repeatedly — this is the Agent Loop.
A truly reliable Loop isn't just about keeping the Agent moving. It's about making sure the Agent knows what the goal is, what it must not touch, how to tell whether the result is correct, and what to do when something fails. Otherwise, it might change a lot of code, run a lot of tests, and still be unable to prove the task is actually done.
This is what Loop Engineering and Harness Engineering aim to solve: preparing the project context, relevant development tools, validation methods, and clear safety boundaries for the Agent, making every Loop closer to reliable delivery.
In Qoder IDE, Loop Engineering covers the following asset types: Rules, Skills, Hooks, MCP configurations, Custom Agents, Plugins, and Session Insights.
## Why you need Better Harness
Building good Loop Engineering is hard. Rules that should exist are only in someone's head. Recurring feedback never gets fixed into a rule. Team conventions live in Slack threads instead of `AGENTS.md`. Most teams don't have the bandwidth — or a clear standard — to sit down and get it right.
**Better Harness** is our attempt to close that gap. It's an Agent that reviews your project's Loop Engineering for you, tells you which parts are strong and which are weak, and — for every gap it finds — can start a fix task with one click.
In the latest Qoder IDE, you can enter Better Harness through the visual interface to launch an analysis and fix issues, or run `/better-harness` directly. It analyzes how the Agent executes tasks, identifies missing or weak key elements, and helps you understand what to strengthen next.
## How Better Harness works
Better Harness checks not just a single answer, but the entire harness supporting the Coding Agent: whether goals and context are clear, whether the project is easy to run, whether permissions are controlled, whether validation is effective, whether delivery is safe, and whether the team and Agent can continuously learn from tasks.
The main analysis process:
1. **Map the current Harness** — identify goals, context, execution entry points, feedback loops, delivery mechanisms, and learning capture.
2. **Find breakpoints** — explain which link is missing a mechanism, integration, actual execution, or evidence of results.
3. **Choose the minimal improvement vehicle** — assign the problem to the most appropriate Rule, Skill, Hook, script, automation, or human gate.
4. **Fix and verify** — scope the repair, run relevant validation, then re-run `/better-harness` to check whether the Loop has actually improved.
During analysis, Better Harness has a main analysis flow that collects raw data, then hands it to three independent read-only sub-Agents that each interpret a different category of evidence: **Agent customization assets** (whether Rules, Skills, Hooks, and other configurations are complete and usable), **real task session records** (what the Agent actually did in real tasks and how it performed), and **project engineering foundations** (whether the project supports the Agent's workflow). The three categories are collected independently and then unified, avoiding conclusions from contaminating each other.
## What Better Harness evaluates
Better Harness scans a project and produces a report along five dimensions:
- **Task Understanding** — whether the Agent can tell what this project is, where a task should start, and how big the change should be.
- **Controlled Execution** — whether the Agent can bring the project up, work inside clear permissions, and stay within its lane.
- **Change Validation** — whether every change is checked against lint, tests, and the like, and whether failures get fixed and re-checked.
- **Reliable Delivery** — whether task results have evidence to accept them, and whether risky actions have approval, rollback, or recovery.
- **Learning Capture** — whether recurring issues become discoverable, reusable rules or Skills that show up on the next similar task.
Each dimension is displayed as a bar chart with a numeric score and the number of related findings. The report also shows your project's current Scope overview (Rules, Skills, Custom Agents, MCPs, Memories, Hooks). Every recommendation can be handed to an Agent with **Plan a fix** — a fix task starts in Quest, the Agent proposes a plan, and you review the change like any other Quest task.
## How to use it
1. Click **Better Harness** at the bottom of the left sidebar (next to Knowledge and Marketplace).
2. Your projects appear as tabs at the top (e.g. air, maERP, condo, twenty, flow). Click a tab to switch; click **+ Add Project** to add a new one.
3. The first time you scan a project, you'll see "Understanding your project structure…" as the Agent maps modules, dependencies, and code relationships. You can track progress via **View in Quest List**.
4. When the report is ready, the overview page displays bar chart scores for the five dimensions, related findings counts, and Scope stats (Rules, Skills, Custom Agents, MCPs, Memories, Hooks).
5. Below the chart, finding cards are listed and can be filtered with **All Findings / Processed / Pending** tabs. Each card shows a priority (High/Medium/Low), title, and dimension.
6. Click **Plan a fix** on a card to start the fix flow. Click **Ignore** to dismiss recommendations you don't need.
7. Use **Regenerate** to run a fresh scan, or **View Details** to open the full report page.

Better Harness doesn't apply fixes on its own. Every fix is a Quest task you can review and roll back — Better Harness only points at what to fix and prepares the prompt.
## Understanding the five dimensions
Checks whether the Agent understands your goal, the relevant context, and the scope of changes — so every task has a clear direction and a clear boundary.
Checks whether the Agent can start and operate the project according to its instructions, and complete the task within clear permissions and operating boundaries.
Checks whether the Agent runs relevant checks for the current change, and whether it can fix failures and validate again.
Checks whether the task result has verifiable evidence for acceptance, and whether high-risk actions have approval, rollback, or recovery options.
Checks whether recurring issues are captured as discoverable, reusable, and maintainable rules, workflows, or tools — and whether their effect is validated in later similar tasks.
## Creating a fix plan
Clicking **Plan a fix** on a card opens a **Finding Detail** dialog containing:
- **Priority** indicator (High / Medium / Low)
- **Issue title** and the dimension it belongs to (e.g. "Repair Plan · Change Validation")
- **Cause** — why the current configuration has this gap
- **Expected Output** — what the fix should achieve
- **Fix Instructions** — an editable prompt pre-filled with a repair plan, starting with `/harness`. You can use it as-is or modify it before confirming.
At the bottom, a model selector and the **Start Fix** button. Clicking it opens a new Quest with the instructions above; track it in your Quest list.
Because fixes flow through Quest, everything the Agent does is inspectable and reversible — no silent edits to your repo.
For every improvement identified, users only need to click **Plan a fix** to have the AI generate and execute the corresponding repair. More importantly, these fixes don't just serve the current task — they can be further distilled into reusable assets like Rules, Skills, and Memories, continuously strengthening your own Agent Harness.
## Viewing the full report
Click **View Details** at the top right of the overview page to open the full report. It includes:
- **Agent Work Loop** — a pipeline visualization showing scores for each of the five dimension nodes.
- **Project Usage** — daily activity heatmap, analyzed session count, estimated active minutes, Skill usage count, and most-used Skills.
- **Prioritized improvements** — all finding cards with **Plan AI Fix** and **View details** actions.
- **Agent Customization** — discovered Loop Engineering assets (Hooks, MCP, Plugins) and coverage status (Rules, Skills, Session Insights, Custom Agents).
- **Evidence & Methods** — sampling confidence, source gaps, and delivery results indicating the data volume behind the conclusions.
- **Long Sessions for Review** — flags sessions exceeding 45 minutes for manual inspection.
- **Session Observations** — representative observations extracted from analyzed sessions to guide investigation priorities.
## Regenerating a report
Reports carry a timestamp (24-hour, local time). As your project evolves, older reports become less relevant. Use **Regenerate** on the report page to run a fresh scan; the newer report replaces the previous one on that project.
Use **Regenerate** when:
- You've merged a batch of Loop Engineering improvements and want to re-check the score.
- The project structure has changed materially (new modules, big refactors).
- The last report is older than a couple of weeks.
## Making every Harness accumulate into future capability
A single `/better-harness` analysis isn't the end. It helps you discover breakpoints, generate fix plans, and verify after fixing whether new Rules, Skills, Hooks, or scripts have truly entered the Agent's work cycle.
More importantly, experiences worth reusing are accumulated as personal or team Agent assets, making subsequent Loops more stable, efficient, and controllable. Now you can enter Better Harness in Qoder IDE, or run `/better-harness`, to see what's most worth strengthening next.
# @Mention
Add context to AI conversations to help AI understand your needs and generate code that follows your project standards. You can add code files, project folders, local attachments, and project rules.
## Ways to add context
| Method | Action | Description |
| ----------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| **Click button** | Click the context selector button `@` in the lower-right corner of the input box | Opens the selector window to browse all context types |
| **Type @** | Type `@` and continue typing | Searches files, folders, and rules in real time with highlighted matches |
| **Drag or paste** | Drag files or images to the chat box | Supports md, xmind, xlsx, docx, pdf, jpg, png |
## Context types
| Type | Purpose | Common scenarios |
| ---------------- | ---------------------------------- | ------------------------------------------------------------------- |
| **@file** | Reference code files or rule files | Query implementations, refactor code, understand modules |
| **@folder** | Reference entire directories | Refactor module structure, generate tests, cross-file queries |
| **@attachments** | Reference local files or images | Generate code from mockups, analyze documents, process spreadsheets |
| **@rule** | Reference project rules | Generate code following team styles, enforce standards |
## @file
Reference code files in your project. Supports querying and modification.
### How to add
- Type `@file` and enter the file name to search
- Drag files from the file explorer to the chat box
> Rule files (such as files in the `.qoder/rules` directory) can also be found via `@file` search.
## @folder
Reference entire directories. Useful when you need to understand or modify a group of related files.
### How to add
Type `@folder` and enter the directory name to search
## @attachments
Reference local files or images to let AI analyze document content, generate code from designs, or process spreadsheet data.
### Supported file types
| Type | Formats | Scenarios |
| ------------ | ------------- | ------------------------------------------------------- |
| Images | jpg, png | Generate frontend code, analyze layouts, extract text |
| Documents | md, pdf, docx | Analyze content, extract information, generate comments |
| Spreadsheets | xlsx | Analyze data structures, generate processing code |
| Mind maps | xmind | Understand architecture, generate code frameworks |
### How to add
- Type `@attachments` to select local files
- Drag or paste files directly to the chat box
- Images are displayed separately at the top of the input box with preview support
## @rule
Reference project rules to make AI follow specific coding styles, framework conventions, or business standards.
Rules are embedded in every model call as persistent, reusable context. They're ideal for defining coding styles, naming conventions, and framework usage patterns that need to stay consistent across your entire project.
### How to add
- Type `@rule` to select configured rules
- When the rule list is empty, create new rules directly via the quick entry without going to the settings page
> Rule files (such as `.md` files in the `.qoder/rules` directory) can be referenced as `@rule` (persistent context) or found via `@file` search (regular file).
## Add to Chat
Files (including code files and Spec files) support fine-grained selection for adding context. You can select any content snippet in a file and add it to the current conversation by:
- Clicking **Add to Chat** in the floating menu
- Using the shortcut `Command+L` (macOS) / `Ctrl+L` (Windows/Linux)
The selected content will be attached as context to the input box, helping the agent understand your intent more precisely.
You can also add content from the conversation flow into the current chat — select a reply or reference a segment in the conversation flow and use **Add to Chat** to attach it to the input box, making it easy to build on earlier context in the same conversation and cut down on retyping.
## **Best practices**
### **Combine context types**
Combine different context types in one prompt:
```
@src/api.js @tests/api.test.js @rule coding-style
Add test cases for this API module and ensure they follow team coding standards
```
### **Leverage recommendations**
After typing `@`, Qoder IDE displays commonly used files at the top of the list:
- **Current file**: The file you're editing
- **Recently opened**: The 2 most recently accessed files
Click recommended files to add them quickly without searching.
### **Use instant search**
After typing `@` and continuing to type, Qoder IDE searches matching files, folders, and rules in real time with highlighted matching characters.
# Voice input
You can use voice input in the chat input box to describe your requirements. This feature applies to Editor and Quest.
**How to use**:
1. Click the **microphone** icon on the right side of the input box.
2. Speak your requirements—your voice will be automatically transcribed into text.
3. Review and edit the transcribed text, then send it.
**Tips**:
- The languages supported by voice input depend on your system's speech recognition service.
- Voice input can be used in combination with manual typing and context attachments.
# One-click prompt optimization
Prompts entered in the chat box can be automatically optimized using attached context and conversation history.
- **Enter a prompt**: Type an initial idea in the input box (for example: "Add a ticket escalation feature").
- **Enhance prompt**: Click the **Enhance prompt ** button on the right side of the input box. The system generates a detailed, actionable prompt based on the input and available context.
- **Review and edit**: The generated prompt includes goals, constraints, and implementation guidance, and can be edited before submission.
- **Undo or submit**: The enhancement can be undone, or the optimized prompt can be submitted directly.
# Indexing
Qoder IDE automatically indexes your codebase by generating file embeddings when you open a project. This enables AI-powered code understanding, intelligent recommendations, and semantic search. Indexing happens incrementally, so new or modified files are processed in real time—no manual intervention required.
## **Configure indexing**
1. In the upper-right corner of your Qoder IDE, click the user icon or use the keyboard shortcut (`⌘` `⇧` `,` (macOS)or`Ctrl` `shift` `,`(Windows)), and select **Qoder IDE Settings**.
2. In the left-side navigation pane, click **Indexing**.
3. Choose one of the following:
- To manually enable indexing, click **Create** next to **Codebase Indexing**.
- To enable continuous background indexing, toggle on **Automatic Indexing**.
> **Note:** **Codebase indexing supports codebases up to 100,000 files**. Automatic indexing is enabled by default for codebases with fewer than 10,000 files. For larger codebases, indexing need to be enabled manually.
## **Ignore files**
By default, Qoder IDE indexes all project files except:
- Files and directories specified in `.gitignore`
- Files listed in `.qoderignore`
### **Specify custom ignore files**
You can define additional files or directories to exclude from indexing.
1. In the upper-right corner of the Qoder IDE, click the user icon or use the keyboard shortcut (`⌘` `⇧` `,` (macOS)or`Ctrl` `shift` `,`(Windows)), and select **Qoder IDE Settings**.
2. In the left-side navigation pane, click **Indexing**.
3. Click **Manage** next to **Ignore Files**.
4. Add your custom patterns.
**Pattern examples**
| **Pattern** | **Description** |
| :---------- | :-------------------------------------------- |
| config.json | Ignores a specific file |
| dist/ | Ignores an entire directory |
| \*.log | Ignores all files with .log extension |
| \*\*/logs | Ignores logs directories at any nesting level |
| !app/ | Excludes a path from being ignored (negation) |
**To check if a specific file is ignored, use the following command:**
`git check-ignore -v [file]`
## **FAQs**
### **Where can I view indexed codebases?**
A centralized index list is not currently available. You can inspect indexed codebases within the indexing settings of each project.
### **Is my source code stored on Qoder IDE servers?**
No. Qoder IDE does not store your source code.
# Rules
Qoder IDE enables project-specific rule configuration. Stored in the `.qoder/rules`directory, these rules apply exclusively to the current project. They optimize model adaptation to your coding preferences—including project frameworks and code styles.
## **How rules work**
Large language models (LLMs) rely on general knowledge, so they lack your project's specific context and rules. Qoder IDE rules address this limitation by strategically injecting predefined context into prompts, which helps guide AI responses to more consistently align with your project’s standards and requirements.
### **Storage and sharing**
- Rule files are stored directly in your project directory and are shared with team members via version control systems like Git, alongside your codebase.
- For local-only rules (not shared), add the `.qoder/rules` directory to your project's `.gitignore` file.
### **Limitations**
- Allows a maximum of **100,000 total characters across** **all active rule files** (excess content will be truncated).
- Supports natural language only—no images or links.
## **Rule types**
| **Type** | **Description** | **Use case** |
| :------------- | :---------------------------------------------------------------------------------- | :------------------------------------------------------------------------------ |
| Apply Manually | Applies manually via `@rule` in the Chat panel or inline chat. | On-demand workflows, custom prompts |
| Model Decision | The AI evaluates the rule description in Agent Mode and decides when to apply it. | Scenario-specific tasks (such as generating unit tests or code comments) |
| Always Apply | Applies to all Chat and Inline Chat requests. | Enforcing project-wide standards (such as coding style or documentation format) |
| Specific Files | Applies to all files matching the wildcard patterns (such as `.js`or `src/**/.ts`). | Programing language- or directory-specific rules |
## **AGENTS.md Compatibility**
Qoder IDE rules are now compatible with AGENTS.MD. To enable this functionality:
1. Simply copy your `AGENTS.md` file to your project directory
2. The Agent will automatically recognize and utilize the rules defined in the file
3. No additional configuration is required - the integration works seamlessly
This compatibility allows you to leverage existing AGENTS.md configurations within the Qoder IDE rules framework, providing a smooth transition and enhanced functionality for your AI-assisted development workflow.
> In case of conflicts between AGENTS.md content and rules content, rules content takes precedence.
## **Best practices**- **Be concise**: Keep rules focused and unambiguous.
- **Structure clearly**: Use bullets points, numbered lists, or Markdown formatting for readability.
- **Include examples**: Provide "good" code samples to guide the model.
- **Iterate and optimize**: Refine rules based on model output and feedback.
## **Configure rules**
1. In the upper-right corner of your Qoder IDE, click the user icon or use the keyboard shortcut (`⌘` `⇧` `,` (macOS)or`Ctrl` `shift` `,`(Windows)), and select **Qoder IDE Settings**.
2. In the left-side navigation pane, click **Rules**.
3. Click **Add**.
4. In the search bar at the top, enter a unique rule name and press **Enter**.
5. Select a rule type:
- **Apply Manually**
- **Model Decision**: Enter scenario description.
- Example: "Generate a unit test."
- **Specific Files**: Provide comma-separated file path wildcards.
- Examples: `*.md`, `src/*.java`.
- **Always Apply**
6. Close the window to save your changes.
## **Next steps**
To edit or delete an existing rule, click the corresponding icon on the **Rules** page.
# Context compression
The AI uses a context window—its short-term memory—to keep track of your conversation. It processes your latest message along with previous ones that fit within this window, which has a fixed size measured in tokens. The longer the chat, the more tokens each message uses.
## How it Works
Qoder IDE’s **Smart Context Control** gives you visibility and control over your conversation’s context window to help you balance detail, performance, and cost.
The system continuously monitors your token usage. When your conversation reaches a threshold (typically >40% of the maximum context window), Qoder IDE surfaces two intelligent actions:
### Compact Chat
- **Summarizes** the entire conversation into a concise, dense context that preserves essential logic, decisions, and code.
- **Reduces future token consumption** significantly.
- **Note**: This is a *lossy compression*—minor details may be generalized or omitted for efficiency.
### New Chat
- **Starts a fresh chat** with an empty context window.
- **Ideal** when switching to a completely unrelated task. Prevents irrelevant history from inflating token usage or confusing the model.
> **Smart Context Control is disabled in two scenarios to protect quality**:
>
> - Early in a conversation (when token savings would be negligible).
> - While the AI is generating a response (to avoid interrupting or corrupting output).
# Browser Agent
Browser Agent is a capability extension in Agent Mode that uses a browser to complete tasks. It can open web pages, browse content, click buttons, fill out forms, scroll pages, and take screenshots to provide feedback on page status in a controlled environment, helping you complete automated tasks that "require actual web access."
Simply describe your needs in natural language during an Agent session (e.g., "check the latest prices on the official website and summarize the differences"), and the Agent will automatically dispatch the Browser Agent when needed, without requiring you to manually switch modes or write scripts.
## **Core Capabilities**
The Browser Agent has the following main capabilities:
- **Open and Navigate Web Pages**
- Open specified web pages based on URLs you provide.
- Jump to new pages or tabs within the same site, such as clicking navigation links or pagination links.
- Support multi-step navigation tasks, such as "open page A -> click menu B -> enter detail page C."
- **Read and Extract Information**
- Read visible text content on the current page, such as titles, paragraphs, lists, and tables.
- Extract key information from pages and summarize or compare it for you in natural language.
- "Search" for relevant information on a page based on your instructions, such as "find price-related content on this page."
- **Interact and Operate Pages**
- Click buttons, links, switch tabs, or expand/collapse folded content.
- Enter text in input boxes, search boxes, and other form elements, and submit forms.
- Scroll through pages to browse more content and avoid missing key information.
- **Visual Feedback and Status Awareness**
- Take screenshots of the current page status as needed when performing complex steps, for subsequent judgment and explanation.
- Sense whether the page has finished loading, whether a form has been successfully submitted, whether it has jumped to a new page, etc., to decide the next operation.
## **Usage Scenarios**
You can consider using the Browser Agent in the following scenarios:
- **Information Retrieval and Comparison**
- Visit product websites, documentation sites, or blogs to extract key information and generate summaries.
- Compare multiple pages or multiple solutions, such as price, feature, or configuration differences.
- **Online Operations and Process Walkthroughs**
- Walk through a "web-based" operation process, such as registering an account or submitting a work order (provided permissions allow and risks are controllable).
- Help you organize typical usage steps for a web backend system and output a draft of operation instructions.
- **Assist Development and Testing**
- Open online documentation or API references to extract parts relevant to your current code.
- Browse the interface of a web application to help you check page structure, copy, or interaction logic, and provide optimization suggestions.
> It is recommended to specify goals and constraints in the task description (e.g., "read only, do not submit any forms" or "only access public documentation pages") to help the Agent complete tasks more safely and stably.
## **Browser type**
Browser Agent supports two browser types that you can switch between based on your needs:
- **Built-in browser**: A lightweight browser panel built into the IDE — no additional setup required, suitable for quick previews and simple page interactions.
- **Chrome**: Uses your local Chrome browser for execution, supporting more complex web applications and pages that require specific browser features or extensions.
You can switch between browser types in the Browser Agent settings.
## **How to Use in Agent Mode**
Browser Agent is built into Agent Mode and requires no separate configuration. You can invoke it in two ways:
1. Automatic invocation: Agent Mode intelligently determines when Browser Agent is needed based on your request.
2. Explicit invocation: Use the `/browser` command to explicitly request Browser Agent.
Detailed usage steps:
Open Qoder IDE's chat panel and switch to Agent Mode
Choose to use `/browser` for explicit invocation, or directly describe your needs in natural language, for example:
`/browser Open https://example.com and summarize the main features`→ Try in Qoder IDE
`/browser Check the 2025 pricing plans and organize them into a table`→ Try in Qoder IDE
`/browser Analyze the theme customization options in this component library`→ Try in Qoder IDE
Browser Agent will:
- Execute necessary web interactions
- Provide detailed explanations of actions taken
- Share screenshots for visual verification
- Present extracted data in structured format
## **Usage Suggestions and Best Practices**
- **Clarify Goals and Boundaries**
- Try to explain "the result to be achieved" in one sentence, rather than just describing a single operation.
- For security or permission-sensitive operations, clearly state "do not perform submission/payment/deletion operations."
- **Provide Stable Entry Links**
- Prioritize providing specific page URLs rather than vague search terms, which can reduce navigation interference.
- If you need to operate across multiple pages, you can list key pages or paths in the prompt.
- **Moderately Split Tasks**
- For very long processes (such as complex configuration wizards), you can split them into multiple small goals, execute them step by step, and confirm intermediate results.
- After each stage ends, adjust the next instruction appropriately based on the results returned by the Browser Agent.
## **Safety and Limitations**
When using Browser Agent, please note the following:
- **Permissions and Privacy**
- Avoid having the Browser Agent enter or expose any sensitive information (such as passwords, access tokens, personal privacy data, etc.) on web pages.
- For operations involving account login, payment, or data writing, please prioritize manual completion, and then let the Agent perform read-only verification or explanation.
- **Page Compatibility and Stability**
- Some sites that rely heavily on front-end frameworks or complex interactions may have slow loading or difficulty identifying elements.
- If page structure or copy changes frequently, some steps may fail to execute. In this case, you can provide a more explicit description or switch to a more stable entry page.
- **Result Reliability**
- Browser Agent's answers are based on real-time accessed web page content, but the web page itself may not be authoritative information. It is recommended to verify yourself before making key decisions.
- For scenarios requiring legal, compliance, or high-risk business judgment, you should not rely solely on the automated results of Browser Agent.
Through Browser Agent, you can enable Qoder IDE to not only "understand your code" but also "understand the web pages you are visiting," completing code editing and web page operation collaboration in the same conversation, greatly reducing the cost of switching back and forth between browsers and IDEs.
# Planning Agent
## **Overview**
The Planning feature allows Agent Mode to create an **implementation proposal and plan** before modifying code or executing commands.\
For medium to large tasks (such as multi-file feature development, refactoring, or high-risk changes), Planning provides clear visibility, controlled execution flow, and a definite implementation path.
With Planning enabled, Qoder IDE generates a structured proposal and plan based on your natural language requirements. You can review and adjust this plan before letting the agent execute it step by step automatically.
## **When to Use Planning**
We recommend enabling Planning in the following scenarios:
- Handling **complex features** that involve multiple modules or files.
- Expecting **multiple iterations** (design, implementation, testing, cleanup, etc.).
For smaller changes (such as "fix a typo" or "rename a variable"), you can directly use the agent to execute and save time without using Planning.
## **How to Use Planning in Agent Mode**
The Planning agent is built into Agent Mode and requires no separate configuration. You can invoke it in two ways:
- Automatic invocation: Agent Mode will intelligently determine when planning is needed based on your request.
- Explicit invocation: Use the /plan command to explicitly request the Planning agent.
Detailed usage steps are as follows:
### **1. Describe Your Task**
Choose to explicitly invoke using /plan, or directly describe your requirements in natural language. When describing, we recommend including the following information:
- The goal of the change or the feature to be implemented.
- Any constraints (such as "cannot break existing API" or "must maintain current behavior for legacy paths").
- Optional: mention important file or module paths.
The clearer and more specific your description, the better the generated plan will match your actual needs.
### **2. Generate a Plan**
When Planning is enabled in the session, Qoder IDE will:
- Analyze your requirements and relevant engineering context.
- Generate a complete plan for you based on requirements, including objectives, technical approach, tech stack, implementation plan, and more.
At this stage, no files are modified and no commands are executed—the output is only a reviewable plan.
### **3. Review and Adjust the Plan**
Before execution begins, you can modify the plan according to your expectations, such as:
- Edit the proposal content to make it more precise and understandable.
- Add steps that the AI didn't cover but you consider important.
You can also directly collaborate with Qoder IDE in natural language to adjust the plan, such as: "Add a step to update documentation at the end."
### **4. Start Execution**
Once you confirm the plan is correct, you can start execution:
- The agent will read files, modify code, run commands, or call MCP tools just like in normal Agent Mode.
- To-do statuses will be updated in real-time at the bottom of the chat (not started/in progress/completed).
Depending on your settings, some operations (especially terminal commands or MCP tool calls) may still require manual confirmation before execution.
### **5. Adjustments During Execution**
During plan execution:
- You can view status changes for each to-do item at any time.
- If you find issues with the plan itself or execution results, you can pause, explain new requirements in the chat, and then let Qoder IDE update the plan before continuing.
- For blocking issues (such as test failures, missing dependencies, etc.), Qoder IDE will clearly indicate them in the conversation and plan the next steps accordingly.
This way, you always maintain decision-making power while the agent handles the specific mechanical work.
### **6. Wrap-up and Review**
After all to-do items are completed (or you actively terminate execution):
- Qoder IDE can summarize what work was completed step by step during this execution (such as which files each To-do modified).
- You can combine the diff view, local testing, or PR workflow to perform normal code review of the final results.
- If there are follow-up work requirements, you can start a new Planning process again to continue iterating.
## **Best Practices**
- **Clearly describe goals**: Write your first prompt as if assigning a task to a colleague, explaining the scope, constraints, and acceptance criteria.
- **Enable Planning by default for high-risk tasks**: Such as refactoring, interface adjustments, changes involving core paths, etc.
- **Iteratively optimize the plan**: If the first version of the plan is not ideal, you can have Qoder IDE adjust it, such as "focus more on the testing part" or "minimize changes to public interfaces."
- **Keep each step small enough**: A good to-do item should allow you to see its scope of impact within a relatively small diff.
By leveraging Planning, you can maintain the high efficiency of the agent while obtaining a carefully designed implementation proposal, achieving a better balance between safety and efficiency.
# Ultra Review Agent
Ultra Review is Qoder IDE's next-generation code review capability. Instead of a single pass-through review, it breaks the review into multiple independent dimensions that run in parallel, then merges and deduplicates the results to produce a structured report with a higher signal-to-noise ratio and more precise issue localization.
## Core capabilities
- **Multi-dimensional parallel review**: Requirement completeness, coding correctness, and change impact are evaluated simultaneously in a single review pass
- **Strict finding threshold**: Each finding must meet all three criteria — confirmed (not speculative), introduced by the current change, and backed by citable evidence — filtering out speculative and unrelated issues
- **Precise code pinpointing**: Every issue is anchored to a specific file and line number, with evidence snippets and actionable fix suggestions
- **Severity grading**: Findings are categorized into three levels — Critical (must fix) / Warning (should fix) / Suggestion (consider fixing)
- **Single-point fault tolerance**: When a dimension produces no output due to the target scope, the other dimensions still return their conclusions normally, with the missing dimension noted in the report
## Three parallel perspectives
Ultra Review splits the review into three independent dimensions running in parallel, each focused on a single concern to avoid cross-dimension interference and diluted depth:
- **Completeness**: Does the change truly implement the intended requirements? Are acceptance criteria, API contracts, and state branches all covered, or is there missing or half-implemented logic?
- **Correctness**: Logic flaws, null pointer and out-of-bounds errors, error handling and edge cases, concurrency and resource leaks, and obvious security or performance risks.
- **Impact**: Side effects introduced by the change (global state, IO, concurrency, lifecycle hooks), and breaking changes to existing contracts (API, defaults, schema, backward-compatible configuration).
Findings from all three dimensions go through a unified merge and deduplication pass — issues hitting the same code location are consolidated into a single entry, keeping the one with the strongest evidence.
## Review scope
`/ultra-review` reviews the following scope by default:
1. Uncommitted code changes (both staged and unstaged) are reviewed first
2. If there are no uncommitted changes, it automatically falls back to the most recent commit
3. You can also explicitly specify a target, such as a commit hash, file path, Pull Request, or a code snippet
## How to use
Ultra Review is built into Qoder IDE — no additional setup required. Use the `/ultra-review` slash command in the input box and optionally specify the review scope.
Ultra Review is currently not available in Quest window's agent mode.
## Best practices
For large changes, review in batches by module or by commit for more granular feedback.
If the change involves specific business context or implicit constraints, briefly describe the context in your request for more relevant review conclusions.
# Computer Use Agent
Computer Use is a Qoder IDE capability extension that lets the agent perceive your screen the way a person does and click, type, and scroll on your computer. When a task involves a graphical interface and can't be completed through the command line or an API, the agent can drive desktop apps and browsers directly — while you keep working in the foreground on your own things.
Computer Use is currently in Beta and is available on macOS and Windows — the experience and the underlying capabilities are still being improved.
## **Core Capabilities**
- Reads the visible content of the target app window and understands the layout, button text, form state, and other visual cues.
- Takes screenshots throughout the run to confirm the page has loaded and the previous action took effect before deciding the next step.
- Supports the full range of human input: clicks, double-clicks, drags, text entry, and keyboard shortcuts.
- Operates at pixel-level precision so it can target small UI elements accurately.
- The agent independently drives the mouse, keyboard, and screenshots, deciding each step based on the interface state.
- On macOS, operations run in the background without stealing your foreground focus; on Windows, operations run in the foreground, so you can see the cursor move and each action take place (see the platform differences below).
- Switches between desktop apps and chains multi-step operations into a complete flow.
- Adjusts the next step based on what just happened, instead of replaying a fixed script.
## **Usage Scenarios**
- **Drive desktop apps that lack an API**: when the target app has no CLI or plugin, the agent works the GUI directly — adjusting parameters in a design tool, batch-updating settings in an admin console, and so on.
- **Automate cross-app flows**: when a task spans several apps, the agent switches windows, copies data, and fills forms to complete the workflow end to end.
- **GUI verification and testing**: confirm that a UI change behaves as intended, reproduce a bug that only surfaces in the GUI, or check how the app responds to a specific sequence of actions.
- **Collect and organize information**: pull data out of apps with no export feature, or consolidate information that's scattered across several screens.
> For web apps, prefer the [Browser Agent](/user-guide/chat/browser-agent) first.
## **System Requirements**
- macOS 14 (Sonoma) or later.
- Windows 10 or later.
## **Differences between Windows and macOS**
Windows handles input and window management quite differently from macOS, so we reimplemented the entire desktop-control capability independently on Windows. There are two differences in how it feels to use:
- **Operations happen in the foreground**: Windows' input mechanism requires the target window to be in the foreground to receive actions, so you'll see the cursor move and each action actually take place. Press `Esc` at any time to interrupt.
- **Dialog boxes are recognized**: on Windows, apps like Office often pop up confirmation and warning dialogs. These are separate windows that don't appear in the main window's screenshot. Qoder IDE automatically detects and composites them, so it can recognize and handle these dialogs and won't get stuck on prompts like "Save?".
## **How to Use**
In the input box, use the `/computer-use` slash command to invoke the capability and describe the task in natural language. The session shows the agent's screenshots and progress in real time — interrupt the task or steer it with follow-up messages at any time.
Every mode of the Editor Window supports Computer Use; the Quest Window supports Computer Use only in Experts mode.
## **App Window Snapshot**
When you want to send the frontmost app window into the conversation as context, **double-tap the `Command` key** to capture a snapshot of the current active app window. The screenshot is auto-attached to Qoder IDE's input box as an image, ready to serve as context for your next instruction — no need to switch windows, take a screenshot manually, and upload it.
Useful scenarios:
- Pull a design mockup, prototype, or reference asset from a design tool straight into the conversation as the basis for generating or modifying code.
- When you hit an error or unusual screen in a browser, database client, terminal, or other app, send the snapshot to the agent for triage and analysis.
- While reading API documentation, a technical blog, or a tutorial, snap the key page so the agent can implement the feature or fix the code against the latest reference shown on screen.
To turn the capability off, open Settings, go to **Integrations**, find **App Window Snapshot**, and pick **Disabled** from the dropdown on the right.
## **Permissions and Approvals**
The first time you enable Computer Use, Qoder IDE shows a permission walkthrough that requests two system permissions:
- **Accessibility**: lets Qoder IDE read the UI element tree and perform clicks, typing, and other accessibility actions.
- **Screen Recording**: lets Qoder IDE capture screenshots of the active window so the agent can perceive the interface state.
Click **Open Settings** and the system jumps to the matching settings pane — drag Qoder IDE Computer Use into the application list there to complete the authorization.
When the agent tries to operate a specific app, Qoder IDE asks for your approval. The default is **Ask every time**, and you can change it in settings: open Settings, go to the **Integrations** page, find **Computer Use Agent** under **Built-in Agent**, and click the dropdown on the right to choose an execution policy.
- **Ask every time**: the agent asks for your confirmation each time it needs to drive the desktop.
- **Auto-run**: the agent runs desktop actions on its own, without per-action confirmation.
- **Disabled**: turn Computer Use off entirely.
The same setting controls both the Editor Window and the Quest Window.
## **Cautions**
- **Granting access means granting control**: once enabled, the agent can drive other apps on your computer with the same effect as if you took the action yourself. Disable it in settings when you don't need it.
- **Some actions can't be undone**: the agent's actions inside desktop apps (sending messages, deleting files) may be irreversible. For high-risk scenarios, prefer the **Ask every time** policy.
- **Screen contents are screenshotted**: the agent perceives the interface through screenshots, so anything visible on screen — including sensitive information — may be captured. Close windows that contain passwords or private data before running automation.
# Custom Agent
Custom Agent is an AI Agent in Qoder IDE designed to handle specific tasks. You can create custom agents to extend Qoder IDE's capabilities, with each agent having its own independent context window, tool permissions, and system prompt. Currently, the scheduling method for custom agents is through the subagent approach.
## Create a Custom Agent
### Method 1: Using create-agent (Recommended)
Qoder IDE provides a built-in `create-agent` skill that helps you quickly create custom agents through interactive guidance.
**Usage**:
```bash
/create-agent
```
`create-agent` will guide you through the following steps:
- Define the agent's name and description
- Select required tool permissions
- Automatically generate system prompt template
- Save the agent file to the correct location
If this is your first time creating a custom agent, we recommend using `/create-agent` to automatically generate the configuration file, ensuring correct formatting and all necessary fields.
### Method 2: Manual Creation
You can also manually create a `.md` file in one of the following locations:
| Scope | Path | Availability |
| ------------- | ----------------------------------------- | -------------------- |
| User-level | `~/.qoder/agents/.md` | All projects |
| Project-level | `${project}/.qoder/agents/.md` | Current project only |
The file should contain a frontmatter block defining basic information, followed by the system prompt content:
```markdown
---
name: code-review
description: Code review expert, checks code quality and security
tools: Read, Grep, Glob, Bash
model: "[ModelName](modelId)"
skills:
- {skillName1}
- {skillName2}
mcpServers:
- {mcpServerName1}
- {mcpServerName2}
---
You are a senior code reviewer responsible for ensuring code quality.
Review checklist:
1. Code readability
2. Naming conventions
3. Error handling
4. Security checks
5. Test coverage
```
| Field | Required | Description |
| ------------- | -------- | ------------------------------------------------------------------------------------- |
| `name` | Yes | Unique identifier for the Custom Agent |
| `description` | Yes | Brief description of functionality and expertise, used for automatic selection |
| `model` | No | Specify the model to use. If not set, follows the model selection in the conversation |
| `tools` | No | List of allowed tools, comma-separated |
| `skills` | No | List of allowed skills |
| `mcpServers` | No | List of allowed MCP servers |
#### MCP servers
Custom agents support configuring MCP (Model Context Protocol) servers, enabling agents to invoke external tools and services. Add the `mcpServers` field in the agent configuration to associate MCP servers, extending the agent's capabilities.
#### Model configuration
Custom agents support specifying which model to use. In the Quest view, go to **Setting → Agents**, select the target agent and click **Change Model** to assign the most suitable model for each agent's role.
#### Tools List
| Tool Name | Description |
| ----------- | ------------------------------------------ |
| `Bash` | Execute shell commands in your environment |
| `Edit` | Make targeted edits to specific files |
| `Write` | Create or overwrite files |
| `Glob` | Find files based on pattern matching |
| `Grep` | Search for patterns in file content |
| `Read` | Read the contents of files |
| `WebFetch` | Fetch content from a specified URL |
| `WebSearch` | Perform web searches with domain filtering |
## Using in IDE
There are two ways to invoke custom agents:
### Method 1: Automatic Trigger
In the Chat panel, describe the task in natural language, and the model will automatically recognize the intent and select the appropriate custom agent based on description:
```
Help me review the implementation of this interface
```
The model will automatically identify and invoke the `code-review` agent.
### Method 2: Manual Trigger
Use `/agent-name` to manually trigger a specific agent:
```
/code-review
```
## Detailed Documentation
For a complete guide on Custom Agents, including automatic creation and CLI usage, see [Subagent Documentation](/cli/subagent).
# Skills
Skills are a mechanism in Qoder IDE for packaging domain expertise into reusable capabilities. Each Skill contains a `SKILL.md` file that defines the skill's description, instructions, and optional auxiliary files. Skills work identically in both Qoder IDE and CLI.
**Key features**:
- **Intelligent invocation**: The model autonomously decides when to use a Skill based on user requests and descriptions
- **Modular design**: Each Skill focuses on solving a specific type of task
- **Flexible extension**: Supports both user-level and project-level custom Skills
## Use Cases
**When to use Skills**:
- **Complex specialized tasks**: Workflows requiring domain expertise (code review, PDF processing, API design)
- **Standardized processes**: Tasks following fixed steps (commit conventions, deployment flows)
- **Team knowledge sharing**: Package best practices for team use
- **Repetitive work**: Frequently executed tasks requiring specialized guidance
## Built-in Skills
In the IDE chat or Quest, type `/` to run bundled helpers (examples):
| Name | Purpose |
| :----------------- | :---------------------------------------------------------------- |
| `/create-skill` | Scaffold a new Skill with guidance |
| `/create-skill-ui` | Generate an interactive HTML widget surface for a Skill |
| `/vercel-deploy` | One-click Vercel deploy flow (OAuth and build) |
| `/create-subagent` | Scaffold a custom sub-agent |
| `/canvas` | Create or edit .canvas.tsx visual artifacts in the Canvas preview |
### Skill UI
Skill UI lets agents render interactive HTML components during execution — forms, charts, config panels, and more. The generated components are embedded directly in the conversation flow, so you can interact without leaving the chat. The first time you use a Skill UI, the agent needs to create the interface for that Skill.
In Quest's Agent mode, use the `/create-skill-ui` command. The agent will create an HTML Widget interface for the specified Skill, which you can preview and iterate on in real time before saving as a template file.
### Vercel Deploy
`/vercel-deploy` is a one-click deployment capability in Quest. It automates the entire workflow of deploying your web project to Vercel — from CLI setup and OAuth login to building and production deployment.
Use the `/vercel-deploy` command in the Quest conversation, and Qoder IDE will automatically start the deployment workflow. On the first deployment, Qoder IDE will guide you through Vercel OAuth login. Follow the prompts to complete account linking in your browser. Once authorized, Qoder IDE will automatically build your project and deploy it to Vercel's production environment. After a successful deployment, you'll receive a live URL.
- **Vercel account required**: Make sure you have a Vercel account before deploying. You can create one during the authorization flow if you don't have one yet.
- **Project must be a buildable web app**: Vercel supports Next.js, React, Vue, Svelte, and other major frameworks. If the project lacks a valid build configuration, deployment may fail. Verify that your project builds successfully locally before deploying.
## How to Use
There are two triggering methods:
1. **Automatic Trigger**: Describe your need directly, and the model will automatically determine whether to use an appropriate Skill:
```
Analyze the errors in this log file
```
The model will automatically recognize and invoke the `log-analyzer` Skill.
2. **Manual Trigger**: Use `/skill-name` to trigger manually:
```
/log-analyzer
```
## Creating Skills
You can create or obtain custom Skills in three ways:
### 1. Auto-create with Built-in Skill
`create-skill` is Qoder IDE's built-in skill creation assistant. It guides you step-by-step through an interactive dialogue to create SKILL.md files that conform to specifications.
**Usage**:
```bash
/create-skill
```
If you're unfamiliar with the SKILL.md file format, we recommend using `/create-skill` first to generate an initial template, then adjust and optimize it based on your actual needs.
**Use case**: Quickly create custom skills without needing to understand the detailed skill file format.
### 2. Install via Skills CLI
Use the [skills CLI](https://github.com/vercel-labs/skills) to install third-party Skills from the [skills.sh](https://skills.sh) marketplace or GitHub with one command.
Execute the following commands in the Qoder IDE terminal:
```bash
# Install from skills.sh marketplace
npx skills add vercel-labs/agent-browser -a qoder
# Install specific skill from GitHub repository
npx skills add https://github.com/anthropics/skills --skill skill-creator -a qoder
```
> See [skills CLI documentation](https://github.com/vercel-labs/skills) for more usage patterns.
**Use case**: Install mature, community-shared skills for ready-to-use functionality.
### 3. Create Manually
If you want to fully customize a skill, you can manually create a SKILL.md file and place it in the specified directory.
**Steps**:
1. Create the skill directory and SKILL.md file
2. Place the file in one of the following paths:
| Location | Path | Scope |
| ------------- | --------------------------------------- | ----------------------------- |
| User-level | `~/.qoder/skills/{skill-name}/SKILL.md` | All projects for current user |
| Project-level | `.qoder/skills/{skill-name}/SKILL.md` | Current project only |
3. Restart Qoder IDE and type `/` in the dialog to view the loaded Skills list
> **Note**: When a skill with the same name exists at both user-level and project-level, the project-level skill takes priority.
**Use case**: Need to fully customize skill content or directly import existing skill files.
## Example Scenarios
### Log Analysis
Create a `log-analyzer` Skill that automatically activates when you say "analyze this log", helping identify errors, performance issues, and anomaly patterns.
### API Documentation Generation
Create an `api-doc-generator` Skill that automatically identifies API endpoints and generates standard documentation and OpenAPI specs.
### Code Review
Create a `code-reviewer` Skill that automatically reviews code according to team standards, checking for potential issues and best practices.
## Full Documentation
For the complete guide on Skills, including how to create them, write SKILL.md files, best practices, and troubleshooting, see [Skills Full Documentation](/cli/Skills).
# Plugins
**Plugins** are bundled packages of any combination of Skills, MCP Servers, Agents, Commands, Rules, and Hooks. By installing a plugin, you can add a coordinated set of capabilities to Qoder IDE at once, covering the entire development lifecycle from coding and testing to deployment.
## Plugin components
A plugin can bundle any combination of the following components:
| Component | Description |
| --------------- | ---------------------------------------------------------------------- |
| **Skills** | Specific agent capabilities for complex tasks |
| **MCP Servers** | Model Context Protocol integrations for external services |
| **Agents** | Sub-agents that can be dispatched by the main Agent for specific tasks |
| **Commands** | Slash commands for user-triggered shortcuts |
| **Rules** | Behavioral and style constraints injected into AI context |
| **Hooks** | Scripts that execute automatically at specific event points |
## Plugin marketplace
Click **Marketplace** at the bottom of the Quest left sidebar, or click the **Marketplace** link in the top right of the Plugins panel in Qoder IDE Settings.
### Discover and browse
Plugins are organized by category to help you find the right capabilities quickly:
| Category | Description |
| ------------------- | ---------------------------------------- |
| **Featured** | Editor-curated popular plugins |
| **Coding** | Code development tools |
| **DataBase** | Database operations and management tools |
| **Workflow** | Workflow orchestration and automation |
| **DevOps** | Deployment, CI/CD, and operations tools |
| **Product Design** | Product design and prototyping tools |
| **Debug & Testing** | Debugging and testing utilities |
Each plugin card displays its name, description, author, download count, and install status. Use the search bar in the top right to find plugins by keyword. You can also filter by tags and install status.
Click a plugin card to open its details page, which shows:
- **Component list** — The Skills, MCP Servers, Agents, Commands, Rules, and Hooks included in the plugin
- **Plugin information** — Category tags, developer, last updated, and source code link
### Install plugins
When installing a plugin, you can choose the scope:
- **User level** — Applies to all your sessions
- **Project level** — Only takes effect in a specific project
Plugins are installed as a whole — installing only selected components from a plugin is not supported. Installed plugins are available in both Editor and Quest.
## Custom plugins
### Create plugins
Click **+ Create Plugin** in the top right of the marketplace. The system will navigate to the Chat area and automatically select the built-in `plugin-creator` Skill, guiding you through creating a custom plugin via conversation.
### Import plugins
You can import existing local plugins into Qoder IDE. Click **+ Create Plugin** and select the option to import from a local folder.
## Use plugins
Once installed, plugins can be invoked in several ways:
- **Automatic triggering** — When you describe a task, Qoder IDE automatically identifies and invokes matching plugin capabilities
- **Slash command** — Type `/plugin-name` in the chat input to invoke a specific plugin directly
- **Try out** — Click the **Try now** button on a plugin card to start a chat session with an Agent and test the plugin
## Manage plugins
You can manage plugins from several entry points:
- Top right of the marketplace → click **Manage** to open the management page
- Bottom of the marketplace category list → click **Installed** to filter installed plugins
- Qoder IDE Settings → open the **Plugins** panel to manage in one place
The Plugins panel is available in Qoder IDE Settings for both Editor and Quest, with the same functionality.
The Plugins panel in Qoder IDE Settings is organized by **User** / **Project** tabs. The **Import** and **+ New** buttons are available at the bottom of the **Custom** section. The **Marketplace** link in the top right lets you jump directly to the marketplace.
Disabling a plugin disables all its bundled components at once — no need to toggle them individually.
### Component association
Components that belong to a plugin (such as Skills, MCP Servers, Agents, etc.) are marked with **From Plugin** in their respective Settings panels. These components are managed by their parent plugin — they cannot be individually disabled, deleted, or modified. Manage them through the plugin instead.
# MCP
Model Context Protocol (MCP) extends Qoder IDE's capabilities by enabling seamless integration with external systems and data sources. This topic covers the core concepts, supported transport types, configuration steps, and practical use cases for MCP.
## What is MCP?
[MCP](https://modelcontextprotocol.io/introduction) is an open protocol that standardizes how applications provide context and tools to large language models (LLMs). By exposing functionality through a consistent interface, MCP allows LLMs to interact with external systems—such as APIs, databases, and local tools—in a structured and secure way.
### Why use MCP
MCP enables Qoder IDE Agent to connect with a wide range of external systems and data sources via standardized interfaces. This enhances the agent's ability to:
- Retrieve real-time information
- Perform actions in external systems
- Process structured or unstructured data
It supports personalized workflows and empowers developers to build more intelligent, context-aware AI assistants.
### How it works
MCP servers expose their capabilities (such as functions and data access) through the MCP protocol. Qoder IDE discovers and invokes these capabilities based on user input and tool metadata.
Qoder IDE supports two standard transport types:
- **Standard Input/Output (STDIO)**
- Communication occurs through stdin/stdout streams.
- Ideal for local tools and command-line integrations.
- Requires local environment setup—best suited for professional developers.
- **Server-Sent Events (SSE)**
- Uses HTTP POST for client-to-server requests and event streams for server-to-client responses.
- Hosted remotely—easy to configure and use.
- Highly recommended for beginners and quick prototyping.
- Also supports Streamable HTTP
## Configure MCP servers
### Open MCP settings
1. In the upper-right corner of your Qoder IDE, click the user icon or use the keyboard shortcut (`⌘` `⇧` `,` (macOS) or `Ctrl` `Shift` `,` (Windows)), and select **Qoder IDE Settings**.
2. In the left-side navigation pane, click **MCP**.
### Option 1: Connect your own MCP server
1. On the **My Servers** tab, click **+ Add** in the upper-right corner.
2. In the JSON file that appears, add your server details:
- Name
- Transport type (STDIO, SSE)
- Command and arguments (for STDIO)
- Endpoint URL (for SSE or Streamable HTTP)
> **Note:** for Streamable HTTP, configure the endpoint the same way as SSE and Qoder IDE will automatically detect and use it
Example:
```json
{
"mcpServers": {
"github": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": ""
}
}
}
}
```
3. Close the file and click **Save** when prompted.
After saving, the new server appears in your list. The link icon means the connection is successful. Expand the entry to view the available tools.
> **Tip:** In the server details, you can configure the per-request timeout using the **Request Timeout** drop-down. If a request runs longer than this value, Qoder IDE stops the call and shows a timeout message in the chat.
### Option 2: Use an MCP server from MCP Square
1. Click the **MCP Square** tab.
2. Browse the list of available servers and click **Install** on the one you want.
> **Note:** Some MCP servers require additional environment variables—such as `API_KEY` or `ACCESS_TOKEN`—to function. These must be configured manually.
3. Go to the **My Servers** tab to confirm the installation. Expand the details to see the tools list.
> **Note:** If a server fails to start due to missing dependencies, click **Quick Fix**. If the issue persists, install the dependencies manually. For troubleshooting, see [MCP common issues](https://docs.qoder.com/troubleshooting/mcp-common-issue).
## Use MCP tools
Qoder IDE automatically selects the appropriate MCP tool based on:
- Your input prompt
- The tool's name and description
Before Qoder IDE calls an MCP tool, you are prompted with a confirmation. To automatically run all the subsequent MCP servers, select this confirmation. Then, the agent uses the tool's output to proceed with the next steps in the workflow.
### Steps
1. In the Chat panel, switch to Agent mode and enter your prompt.
2. Before calling a tool, Qoder IDE prompts for confirmation. Press `⌘` `⏎` (macOS) or `Ctrl` `Enter` (Windows) to execute.
3. After execution, the result appears in the chat.
Expand the response to view detailed input and output.
4. Review any generated code and accept changes as needed.
## Example scenarios
### Scenario 1: Retrieve and process web content (remote MCP via SSE)
Use an MCP server to fetch and convert web content from HTML to Markdown for easier reading.
**Step 1: Get the MCP SSE server endpoint**
1. Visit the official MCP marketplace website.
2. Copy the SSE endpoint URL for the [fetch server](https://mcpservers.org/servers/modelcontextprotocol/fetch).
**Step 2: Add the MCP server**
In the Qoder IDE IDE, go to the **MCP** page, and edit the MCP server with the following:
- Name:`fetch`
- Type:`SSE`
- Server endpoint: Paste the copied URL.
Example:
```json
{
"mcpServers": {
"fetch": {
"type": "sse",
"url": "https://mcp.api-inference.modelscope.net/******/sse"
}
}
}
```
**Step 3: Complete configuration**
Once saved, the link icon confirms the server is ready. Expand the details to see the tools list.
**Step 4: Use in Qoder IDE**
In Agent mode, enter:
```plaintext
Summarize this document: https://docs.qoder.com/user-guide/chat/overview
```
### Scenario 2: Query city weather (local MCP via STDIO)
Use a local MCP server to retrieve real-time weather data.
**Step 1: Check prerequisites**
Ensure Node.js is installed. You can ask Qoder IDE to verify:
```plaintext
Check my local environment to ensure Node.js is installed
```
**Step 2: Add an MCP server**
In the Qoder IDE IDE, go to the **MCP** page, and edit MCP server with the followings:
- Name:`weather`
- Type:`STDIO`
- Command:`npx`
- Arguments:
```shellscript
-y @h1deya/mcp-server-weather
```
Example:
```json
{
"mcpServers": {
"weather": {
"command": "npx",
"args": [
"-y",
"@h1deya/mcp-server-weather"
]
}
}
}
```
**Step 3: Complete configuration**
Once saved, the link icon confirms the server is ready. Expand the details to see the tools list.
**Step 4: Use in Qoder IDE**
In Agent mode, enter a prompt such as:
```plaintext
Check the weather in San Francisco, United States
```
Then, follow up with:
```plaintext
Are there any weather alerts in the United States tomorrow?
```
## References
- [MCP common issues](https://docs.qoder.com/troubleshooting/mcp-common-issue)
- [Terminal execution exceptions](https://docs.qoder.com/troubleshooting/terminal-execution-exceptions)
# Hooks
Hooks let you run custom logic at key points during Agent execution in the Qoder IDE and JetBrains plugin — no source code changes required. Edit a JSON config file to:
- Block dangerous operations before a tool runs
- Auto-lint after every file write to enforce code style
- Send a desktop notification when the Agent finishes, so you don't have to watch the IDE
Unlike prompt instructions, hooks are deterministic — when the event fires, your script runs. No model interpretation, no drift.
Hook capabilities differ per entry point: this page covers the Qoder IDE / JetBrains plugin (12 events, `command` and `http` handler only). [Qoder CLI Hooks](/cli/hooks) and [QoderWork Hooks](/qoderwork/hooks) are documented separately. Config files are shared between the IDE and the CLI, but each entry point only runs the events it supports.
## Supported Events
The IDE / JB plugin currently supports twelve hook events:
| Event | When It Fires | Blockable |
| ---------------------- | -------------------------------------------------------------- | --------- |
| **SessionStart** | When a session starts or resumes | No |
| **UserPromptSubmit** | After the user submits a prompt, before the Agent processes it | Yes |
| **PreToolUse** | Before a tool executes | Yes |
| **PermissionRequest** | When a tool requires user authorization | Yes |
| **PostToolUse** | After a tool executes successfully | No |
| **PostToolUseFailure** | After a tool execution fails | No |
| **SubagentStart** | When a sub-agent starts | No |
| **SubagentStop** | When a sub-agent stops | No |
| **Stop** | When the Agent completes its response | Yes |
| **SessionEnd** | When a session ends | No |
| **PreCompact** | Before context compaction | No |
| **Notification** | When a user-facing notification is emitted | No |
## Quick Start
Here is an example that blocks `rm -rf` commands:
```bash
mkdir -p ~/.qoder/hooks
cat > ~/.qoder/hooks/block-rm.sh << 'EOF'
#!/bin/bash
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command')
if echo "$command" | grep -q 'rm -rf'; then
echo "Dangerous command blocked: $command" >&2
exit 2
fi
exit 0
EOF
chmod +x ~/.qoder/hooks/block-rm.sh
```
Add the following to `~/.qoder/settings.json`:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/block-rm.sh"
}
]
}
]
}
}
```
Open your IDE and ask the Agent to run a command containing `rm -rf` in the Qoder IDE plugin panel. The hook blocks execution and feeds the error message back to the Agent.
## Use Cases
| Scenario | Event | Description |
| ------------------------ | ------------------ | ---------------------------------------------------------------------------------- |
| Block dangerous commands | PreToolUse | Prevent the Agent from running `rm -rf`, `DROP TABLE`, etc. |
| Validate file paths | PreToolUse | Restrict the Agent to creating or editing files only within a designated directory |
| Auto-lint / format | PostToolUse | Run ESLint / Prettier automatically after every file write |
| Audit logging | PostToolUse | Record every tool invocation for security audits |
| Failure alerting | PostToolUseFailure | Send an alert or write an error log when a tool call fails |
| Prompt content screening | UserPromptSubmit | Detect sensitive data (passwords, keys, etc.) in user input |
| Auto-inject context | UserPromptSubmit | Automatically append project conventions or coding standards to every prompt |
| Desktop notification | Stop | Show a system notification when the Agent finishes |
## How It Works
The hook lifecycle comes down to three steps: **write a script, register it in config, and it takes effect automatically**.
When the Agent reaches a lifecycle event (such as "before a tool call"), the plugin checks whether any hooks are registered for it:
1. The plugin loads all hook configurations at startup.
2. During Agent execution, the plugin encounters a lifecycle event (e.g. `PreToolUse`).
3. The plugin iterates through every hook group registered for that event and evaluates the `matcher` against the current context.
4. Hooks with a matching matcher run their shell scripts in order.
5. Each script receives event context as JSON via `stdin` and returns a decision through its exit code and `stdout`.
6. The plugin reads the result and decides what to do next — proceed or block.
## Prerequisites
- **jq**: The example scripts use jq to parse JSON. Install it with `brew install jq` on macOS or `apt install jq` on Linux.
- **Script permissions**: Every hook script must be executable (`chmod +x`).
## Creating Hooks
### 1. Decide What You Need: Pick an Event and a Matcher
Start by deciding where to intervene and what to match:
```plaintext
I want to intercept/handle [what operation] at [what point]?
↓ ↓
write a matcher pick an event
```
| Requirement | Event | Matcher |
| ---------------------------------------------- | ------------------ | ------------------ |
| Check before the Agent runs any shell command | PreToolUse | `"Bash"` |
| Process after the Agent writes or edits a file | PostToolUse | `"Write\ | Edit"` |
| Log when any tool call fails | PostToolUseFailure | `"Bash"` or omit |
| Screen every user prompt | UserPromptSubmit | Omit (matches all) |
| Trigger a notification when the Agent stops | Stop | Omit (matches all) |
| Intercept only MCP tools | PreToolUse | `"mcp__.*"` |
### 2. Write the Hook Script
A hook script is a standard shell script that follows this protocol:
**Input**: JSON event context delivered via `stdin`.
**Output**: Determined by the exit code.
```plaintext
exit 0 → Allow (continue execution)
exit 2 → Block (stop the action; stderr is injected into the conversation)
other → Error (continue execution; stderr is shown to the user)
```
**Script template:**
```bash
#!/bin/bash
# 1. Read the JSON input from stdin
input=$(cat)
# 2. Extract the fields you care about with jq
# Different events provide different fields — see the "Hook Events" section
tool_name=$(echo "$input" | jq -r '.tool_name')
tool_input=$(echo "$input" | jq -r '.tool_input')
# 3. Write your logic
if [ "$tool_name" = "Bash" ]; then
command=$(echo "$input" | jq -r '.tool_input.command')
# Check for dangerous operations
if echo "$command" | grep -qE 'rm\s+-rf|DROP\s+TABLE'; then
# Block: exit 2 + stderr message is fed back to the Agent
echo "Operation denied: $command" >&2
exit 2
fi
fi
# 4. Allow
exit 0
```
You can also output JSON on `stdout` when exiting with `exit 0` for finer-grained control:
```bash
#!/bin/bash
input=$(cat)
# Output JSON for fine-grained control (only parsed when exit code is 0)
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"This operation is not allowed"}}'
exit 0
```
### 3. Register the Script in Your Config
Add the script path under the corresponding event in your settings file:
```json
{
"hooks": {
"EventName": [
{
"matcher": "match condition (optional)",
"hooks": [
{
"type": "command",
"command": "path/to/script"
}
]
}
]
}
}
```
### 4. Test and Debug
You can test your scripts directly from the terminal by piping JSON input:
```bash
# Simulate a PreToolUse event
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"},"hook_event_name":"PreToolUse"}' \
| ~/.qoder/hooks/block-rm.sh
echo "Exit code: $?"
```
Check the stderr output (the block message):
```bash
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"}}' \
| ~/.qoder/hooks/block-rm.sh 2>&1
```
## Configuring Hooks
### Config File Locations
Hook configurations are loaded from the following files. When hooks are defined at multiple levels, they are **merged** and executed together (listed from lowest to highest priority):
| Location | Scope | Priority | Shareable | Description |
| ---------------------------- | --------------------- | ---------- | --------- | ---------------------------------------- |
| `~/.qoder/settings.json` | User-level | 1 (lowest) | No | Personal config, applies to all projects |
| `.qoder/settings.json` | Project-level | 2 | Yes | Commit to Git and share with your team |
| `.qoder/settings.local.json` | Project-level (local) | 3 | No | Gitignored; for your personal dev setup |
The IDE / JB plugin and the CLI share the same config files. Hot reload is not yet supported — restart the IDE after editing hook configurations for changes to take effect.
### Config Format
```json
{
"hooks": {
"EventName": [
{
"matcher": "match condition",
"hooks": [
{
"type": "command",
"command": "command to execute"
}
]
}
]
}
}
```
| Field | Required | Description |
| --------------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| `type` | Yes | `"command"` or `"http"` |
| `command` | Yes | Shell command or path to the script to run |
| `timeout` | No | Timeout in seconds (defaults to 30) |
| `matcher` | No | Match condition. If omitted, the hook fires on every occurrence of that event |
| `if` | No | Finer per-hook condition, e.g. `"ToolName"` or `"ToolName(arg_pattern)"` |
| `async` | No | When `true`, the hook runs in the background without blocking the current operation |
| `asyncRewake` | No | When `true`, runs in the background and can wake the model with its result — useful for long-running checks |
| `statusMessage` | No | Custom description shown in the status line while the hook runs |
You can define multiple matcher groups under a single event, and each group can contain multiple hook commands.
### Matcher Rules
`matcher` determines when a hook fires. What it matches against depends on the event (see each event's description).
| Pattern | Meaning | Example |
| -------------- | --------------------- | --------------------------------------- |
| Omit or `"*"` | Match everything | All tools trigger the hook |
| Exact value | Exact match | `"Bash"` fires only for the Bash tool |
| `\ | `-separated | Match multiple values | `"Write\ | Edit"` fires for Write or Edit |
| Regex | Regex match | `"mcp__.*"` matches all MCP tools |
### Tool Name Mapping
Qoder IDE supports two sets of tool names — native names and Claude Code-compatible names. You can use either in your matchers; the plugin maps them internally. For example, `matcher: "Bash"` is equivalent to `matcher: "run_in_terminal"`.
| Qoder IDE native name | Compatible name | Description |
| ----------------------- | --------------- | ---------------------------------------- |
| `run_in_terminal` | `Bash` | Execute shell commands |
| `read_file` | `Read` | Read file contents |
| `create_file` | `Write` | Create / write a file |
| `search_replace` | `Edit` | Edit a file |
| `edit_file` | - | Diff / code-block based editing |
| `get_terminal_output` | - | Fetch background terminal output |
| `delete_file` | - | Delete a file |
| `grep_code` | `Grep` | Search file contents |
| `search_file` | `Glob` | Match files by name |
| `list_dir` | `LS` | List a directory |
| `Agent` | `Task` | Launch a sub-agent (legacy name: `task`) |
| `Skill` | - | Invoke a skill |
| `search_web` | `WebSearch` | Web search |
| `fetch_content` | `WebFetch` | Fetch web page content |
| `todo_write` | `TodoWrite` | Write a TODO |
| `ask_user_question` | - | Ask the user a question |
| `search_memory` | - | Search memory |
| `update_memory` | - | Update memory |
| `switch_mode` | - | Switch mode |
| `create_plan` | - | Create a plan |
| `run_preview` | - | Preview a web app |
| `get_problems` | - | Read IDE diagnostics |
| `fetch_rules` | - | Load rules |
| `ImageGen` | - | Generate an image |
| `mcp____` | same | MCP tools |
## Writing Hook Scripts
Hook scripts receive JSON input via stdin and communicate results through their exit code and stdout. This section covers the input/output format common to all events. For event-specific fields, see [Hook Events](#hook-events).
### Input
Your hook script receives JSON data via **stdin**. Every event includes these common fields:
| Field | Description | Always Present |
| ---------------------- | ------------------------------------------------------------------------------------ | -------------- |
| `session_id` | Current session ID | Yes |
| `cwd` | Current working directory | Yes |
| `hook_event_name` | Name of the event that triggered this hook | Yes |
| `transcript_path` | Path to the session context JSONL file | Yes |
| `request_set_id` | ID of the current IDE request round | No |
| `tool_name` | Tool name (tool-related events only) | No |
| `tool_input` | Tool input parameters | No |
| `tool_response` | Tool execution result (PostToolUse only). Currently delivered as a string in the IDE | No |
| `extra.email` | User's Git email | No |
| `extra.repo` | Repository path (group/repo format) | No |
| `extra.branch` | Current branch | No |
| `extra.request_time` | Request time (RFC3339) | No |
| `extra.response_time` | Response time (RFC3339) | No |
| `extra.full_diff_text` | Full diff of the change (PostToolUse of edit tools only) | No |
Each event adds its own fields on top of these (see the individual event descriptions). Treat every field as optional — even when a field is declared, a given execution path may not populate it.
Parse the input with `jq`:
```bash
#!/bin/bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.tool_name')
```
### Output
Hooks communicate results through their exit code and stdout.
**Exit code** determines the basic behavior:
| Exit code | Meaning | Behavior |
| --------- | ------- | ------------------------------------------------------------------------------------- |
| `0` | Success | Continue execution; stdout JSON is parsed |
| `2` | Block | Stop the action; stderr is injected into the conversation (only for blockable events) |
| Other | Error | Non-blocking error; stderr is shown to the user; execution continues |
**stdout JSON** provides fine-grained control for certain events. See each event's description for the supported fields. The IDE attempts to parse stdout as JSON for both exit code 0 and exit code 2 — do not assume that exit-2 stdout is treated as plain text.
#### Common stdout fields
Beyond the event-specific fields inside `hookSpecificOutput`, the following top-level fields apply across events:
| Field | Description |
| -------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `systemMessage` | A message surfaced to the user |
| `continueWithPrompt` | Whether the Agent should continue |
| `decision` | `"block"` for a general block decision. Permission decisions use `hookSpecificOutput.permissionDecision` instead |
| `reason` | Reason for the decision (some events define their own reason field) |
| `updatedToolOutput` | Replaces the tool output |
| `hookSpecificOutput` | Container for event-specific fields (see each event) |
### Environment Variables
When a hook script runs, the plugin injects the following environment variables that your script can reference:
| Variable | Description |
| ---------------------------- | ---------------------------------------------- |
| `QODER_SESSION_ID` | Session ID |
| `QODER_TOOL_NAME` | Current tool name |
| `QODER_CWD` | Working directory |
| `QODER_TRANSCRIPT_PATH` | Transcript file path |
| `QODER_TOOL_INPUT_FILE_PATH` | File path the tool operates on (if applicable) |
## Hook Events
### SessionStart
Fires when a session starts or resumes. Use it to inject startup context (project conventions, environment info) at the beginning of a session.
**Matcher:** None.
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "SessionStart",
"type": "startup",
"model": "Auto"
}
```
| Field | Type | Description |
| ------- | ------ | -------------------------------------------------------- |
| `type` | string | Session start type. The IDE currently passes `"startup"` |
| `model` | string | The session's model setting |
**stdout JSON fields (on success):**
```json
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "## Environment\n..."
}
}
```
### UserPromptSubmit
Fires after the user submits a prompt in the IDE plugin panel, before the Agent begins processing it. Use it for prompt screening, content filtering, or auto-injecting context.
**Matcher:** None. This event fires for all user input.
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "UserPromptSubmit",
"prompt": "Write me a sorting function"
}
```
**Blocking the prompt:** Exit with code 2. The stderr content is displayed to the user as an error, and the Agent does not process the prompt.
**stdout JSON fields (when exit code is 0):**
```json
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "## Current Git status\n..."
}
}
```
| Field | Type | Description |
| -------------------------------------- | ------ | --------------------------------------------------------- |
| `hookSpecificOutput.hookEventName` | string | Fixed to `"UserPromptSubmit"` |
| `hookSpecificOutput.additionalContext` | string | Additional context injected into the Agent's conversation |
**Example: Auto-append project conventions to every prompt**
```bash
#!/bin/bash
input=$(cat)
prompt=$(echo "$input" | jq -r '.prompt')
# Automatically append a coding standards reminder
echo '{"hookSpecificOutput":{"hookEventName":"UserPromptSubmit","additionalContext":"Follow the coding standards defined in the project .editorconfig."}}'
exit 0
```
### PreToolUse
Fires before a tool executes. **Can block tool execution.** This is the most commonly used hook event — ideal for blocking dangerous commands, validating file paths, or enforcing permissions.
**Matcher:** Tool name (e.g. `Bash`, `Write`, `Edit`, `Read`, `Glob`, `Grep`, or MCP tool names like `mcp__server__tool`).
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": { "command": "rm -rf /tmp/build" }
}
```
**Blocking tool execution:** Exit with code 2. The stderr content is returned to the Agent as an error. See the [Quick Start](#quick-start) for a full example.
**stdout JSON fields (when exit code is 0):**
```json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "Safe read operation",
"updatedInput": { "command": "npm test --coverage" },
"additionalContext": "Added coverage flag"
}
}
```
| Field | Type | Description |
| --------------------------------------------- | ------ | ---------------------------------------------------------------------------- |
| `hookSpecificOutput.hookEventName` | string | Fixed to `"PreToolUse"` |
| `hookSpecificOutput.permissionDecision` | string | `"allow"` (proceed), `"deny"` (reject), or `"ask"` (prompt the user) |
| `hookSpecificOutput.permissionDecisionReason` | string | Reason for the decision, shown to the Agent / user when denying or asking |
| `hookSpecificOutput.updatedInput` | object | Modified tool input parameters (optional; use this to rewrite the tool call) |
| `hookSpecificOutput.additionalContext` | string | Additional context (optional) |
### PermissionRequest
Fires when a tool call requires user authorization. **Can decide the authorization automatically** — use it to auto-approve safe operations or auto-deny policy violations without a user prompt.
**Matcher:** Tool name.
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "PermissionRequest",
"tool_name": "Bash",
"tool_input": { "command": "rm -rf node_modules" },
"tool_use_id": "call_01ABC123"
}
```
**stdout JSON fields (on success):**
```json
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"permissionDecision": "allow",
"permissionDecisionReason": "Safe cleanup command",
"updatedInput": { "command": "rm -rf node_modules" }
}
}
```
| Field | Type | Description |
| --------------------------------------------- | ------ | ------------------------------------------------------------------------------------ |
| `hookSpecificOutput.permissionDecision` | string | `"allow"` (approve), `"deny"` (reject), or `"ask"` (fall back to prompting the user) |
| `hookSpecificOutput.permissionDecisionReason` | string | Reason for the decision |
| `hookSpecificOutput.updatedInput` | object | Modified tool input parameters (optional) |
The IDE and the CLI use different output structures for this event — the CLI expects a nested `decision.behavior` object. Do not reuse the same script across both products without adapting the output.
### PostToolUse
Fires after a tool executes successfully. Not blockable. Use it for auto-linting, logging, or result analysis.
**Matcher:** Tool name.
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": { "file_path": "/path/to/file.ts", "file_content": "..." },
"tool_response": "File written successfully"
}
```
**stdout JSON fields (when exit code is 0):**
```json
{
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"feedback": "File formatted with Prettier. 3 issues auto-fixed."
}
}
```
| Field | Type | Description |
| ---------------------------------- | ------ | ------------------------------------------------------------ |
| `hookSpecificOutput.hookEventName` | string | Fixed to `"PostToolUse"` |
| `hookSpecificOutput.feedback` | string | Feedback displayed to the user (e.g. a lint results summary) |
### PostToolUseFailure
Fires when a tool call fails. Not blockable. Use it for error monitoring, retry suggestions, or logging.
**Matcher:** Tool name.
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "PostToolUseFailure",
"tool_name": "Bash",
"tool_input": { "command": "npm test" },
"tool_use_id": "call_01ABC123",
"error": "Command exited with non-zero status code 1",
"is_interrupt": false
}
```
| Field | Type | Description |
| -------------- | ------- | ------------------------------------------------- |
| `error` | string | The error message from the failed tool execution |
| `is_interrupt` | boolean | Whether the failure was caused by an interruption |
### Stop
Fires after the Agent completes its response (i.e. the Agent has no more tool calls to make). **Can block the Agent from stopping.** Use it for quality gates, desktop notifications, logging, task status reports, or Harness self-evolution.
**Matcher:** None. This event fires whenever the Agent stops.
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "Stop",
"stop_hook_active": true,
"last_assistant_message": "I've finished writing the sorting function."
}
```
| Field | Type | Description |
| ------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `stop_hook_active` | boolean | `true` when the Agent is retrying after a previous Stop hook block. **Your script must check this field and exit 0 when it is true to prevent infinite loops.** |
| `last_assistant_message` | string | The Agent's last text response |
**Blocking the Agent from stopping:** Exit with code 2. The block reason is injected into the conversation as a user message, and the Agent continues working.
**stdout JSON fields (when exit code is 0):**
```json
{
"decision": "block",
"reason": "Tests failing. Fix them before completing."
}
```
| Field | Type | Description |
| ---------- | ------ | ------------------------------------------------------------------------ |
| `decision` | string | `"block"` (prevent the Agent from stopping and make it continue working) |
| `reason` | string | Reason for blocking; injected into the conversation as a message |
Preventing infinite loops: When a Stop hook blocks the Agent (exit 2), the Agent retries and the Stop event fires again with `stop_hook_active: true`. Your script must check this field and `exit 0` when it is `true`, otherwise the hook will block indefinitely.
### SubagentStart
Fires when a sub-agent starts. Not blockable. Use it for sub-agent auditing or injecting sub-agent context.
**Matcher:** None.
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "SubagentStart",
"agent_id": "a1b2c3d4",
"agent_type": "task"
}
```
**stdout JSON fields (on success):** `hookSpecificOutput.additionalContext` — context injected into the sub-agent's conversation.
### SubagentStop
Fires when a sub-agent stops. Not blockable in the IDE. Use it for logging sub-agent results.
**Matcher:** None.
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "SubagentStop",
"agent_id": "a1b2c3d4",
"agent_type": "task",
"stop_hook_active": false,
"agent_transcript_path": "/path/to/agent-transcript.jsonl",
"last_assistant_message": "Sub-task finished."
}
```
| Field | Type | Description |
| ------------------------ | ------- | ---------------------------------------------------- |
| `agent_id` | string | Sub-agent ID |
| `agent_type` | string | Sub-agent type |
| `stop_hook_active` | boolean | Whether the stop is being retried after a hook block |
| `agent_transcript_path` | string | Path to the sub-agent's transcript file |
| `last_assistant_message` | string | The sub-agent's last text response |
### SessionEnd
Fires when a session ends. Not blockable — use it for cleanup or session archiving side effects.
**Matcher:** None.
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "SessionEnd",
"reason": "exit"
}
```
Read the end reason from the `reason` input field. (Historical matcher metadata used the name `exit_reason`; scripts should rely on the actual `reason` field in stdin.)
### PreCompact
Fires before context compaction. In the IDE this event is for notification and side effects — it cannot block compaction.
**Matcher:** Trigger method (`manual` for user-initiated compaction, `auto` for automatic compaction near the context limit).
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "PreCompact",
"trigger": "auto",
"custom_instructions": ""
}
```
### Notification
Fires when the plugin emits a user-facing notification. Not blockable. Use it to forward notifications to external channels (desktop, IM, etc.).
**Matcher:** Notification type.
**Extra input fields:**
```json
{
"session_id": "abc-123",
"cwd": "/path/to/project",
"hook_event_name": "Notification",
"notification_type": "permission_prompt",
"title": "Permission Required",
"message": "Agent is requesting permission to run: rm -rf node_modules"
}
```
**stdout JSON fields (on success):** `hookSpecificOutput.additionalContext`.
## Things to Keep in Mind
- **Timeout handling:** Hook scripts have a default timeout of 30 seconds, configurable per hook with the `timeout` field. If a script times out, it is killed and treated as an allow (proceed).
- **Error handling:** If a script exits with an unexpected code (anything other than 0 or 2), the error message is shown to the user but the Agent continues without interruption.
- **Script permissions:** Make sure your scripts are executable (`chmod +x`).
- **Config merging:** When the same event has hooks defined at multiple config levels, they execute in order from lowest to highest priority. If any hook blocks (exit 2), the remaining hooks for that event are skipped.
- **jq dependency:** The example scripts rely on `jq` to parse JSON. Make sure it is installed on your system (`brew install jq` on macOS, `apt install jq` on Linux).
## Best Practice Scenarios
### Who Should Use Hooks
Hook value depends on your role. Here's a quick mapping:
#### For Individual Developers
| Scenario | Description | Practice |
| ------------------------------- | ------------------------------------------------------------------------------------ | ---------- |
| **Prompt Enhancement** | Auto-inject project-specific skills and coding standards — no manual input each time | Scenario 1 |
| **Sensitive Data Interception** | Prevent passwords, keys, internal IPs from being sent to the model | Scenario 2 |
| **Dangerous Command Blocking** | Block `rm -rf`, `git push --force`, and other destructive commands | Scenario 6 |
| **Harness Self-Evolution** | Auto-detect reusable lessons at session end and trigger a retrospective | Scenario 8 |
#### For Teams / Enterprises
| Scenario | Description | Practice |
| ------------------------------ | ----------------------------------------------------------------------------------------------- | ---------- |
| **Rule/Skill Usage Analytics** | Track which Rules and Skills fire across the team, assess asset quality | Scenario 3 |
| **File Edit Tracking** | Record which files the Agent modifies, for change audits and impact analysis | Scenario 4 |
| **Global Usage Analytics** | Collect conversation content, tool calls, model replies — full pipeline for efficiency analysis | Scenario 5 |
| **Safety Controls** | Enforce a team-wide dangerous-command blocklist | Scenario 6 |
| **Quality Gates** | Auto-run build/tests before the Agent finishes; block and fix if they fail | Scenario 7 |
Individual scenarios are typically configured in `~/.qoder/settings.json` (user-level) or `.qoder/settings.local.json` (project-level local). Team scenarios should go in `.qoder/settings.json` (project-level) and be committed to Git to ensure uniform enforcement.
### Scenario 1: Prompt Enhancement — Auto-Inject Skills
Pain point: You have to manually specify a Skill every time, or forget to load project-specific context.
Solution: Use a `UserPromptSubmit` hook to auto-inject a prompt hint guiding the Agent to use a specific Skill.
**Config:**
```json
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/inject-skill-hint.sh"
}
]
}
]
}
}
```
**Script** `.qoder/hooks/inject-skill-hint.sh`:
```bash
#!/bin/sh
# 功能:在 Prompt 提交时,注入 Skill 使用提示(每个会话仅注入一次)
INPUT=$(cat)
# === 会话级去重:同一 session 只注入一次 ===
# 未来可使用 SessionStart 事件(即将支持)替代,届时无需去重逻辑
SESSION_ID=$(printf '%s' "$INPUT" | jq -r '.session_id // empty')
DEDUP_DIR="/tmp/hook-dedup"
mkdir -p "$DEDUP_DIR"
if [ -n "$SESSION_ID" ] && [ -f "$DEDUP_DIR/skill-hint-$SESSION_ID" ]; then
exit 0 # 本会话已注入过,跳过
fi
# ============================================
# 读取项目约定的 skill 使用规则(可根据项目自定义)
SKILL_HINT=""
# === 请根据你的项目实际情况修改以下内容 ===
# 示例1:始终提示使用 git-commit skill
# SKILL_HINT="如果用户要求提交代码,请使用 /git-commit skill"
# ============================================
if [ -z "$SKILL_HINT" ]; then
exit 0
fi
# 标记本会话已注入
[ -n "$SESSION_ID" ] && touch "$DEDUP_DIR/skill-hint-$SESSION_ID"
cat <&2
exit 2 # 阻断 Prompt 提交
fi
# ============================================
exit 0
```
**Key points:**
- `UserPromptSubmit` is a **blockable event**; `exit 2` directly prevents the prompt from reaching the Agent
- Sensitive patterns support **regular expressions** for flexible matching (e.g. AWS AKIA prefix, internal IP ranges)
- Consider extracting patterns to a **separate config file** (e.g. `.qoder/hooks/sensitive-patterns.txt`) for team-wide maintenance
- For more precise detection, call external tools like `gitleaks` or `trufflehog`
Difference from Scenario 1:Scenario 1 uses `exit 0` + `additionalContext` for prompt enhancement (injecting context), while this scenario uses `exit 2` for prompt blocking (rejecting non-compliant input). Both can coexist under the same `UserPromptSubmit` event and execute in config order.
### Scenario 3: Rule/Skill Usage Analytics
Pain point: Many Rules and Skills are configured but actual usage rates are unknown.
Solution: Use the Transcript system + `Stop` hook to automatically analyze and record Rule/Skill trigger data after each conversation.
**Config:**
```json
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/analyze-rule-skill-usage.sh"
}
]
}
]
}
}
```
**Script** `.qoder/hooks/analyze-rule-skill-usage.sh`:
```bash
#!/bin/sh
# 功能:在 Agent 完成响应时,分析本次会话的 Rule/Skill 使用情况
INPUT=$(cat)
# 从 stdin 提取字段
TRANSCRIPT_PATH=$(printf '%s' "$INPUT" | jq -r '.transcript_path // empty')
SESSION_ID=$(printf '%s' "$INPUT" | jq -r '.session_id // empty')
if [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
exit 0
fi
# === 📝 分析逻辑 — 请根据实际需求调整 ===
# 1. 提取 session_meta 中的 rules 信息(JSONL 逐行解析)
RULES_META=$(jq -c 'select(.data.meta_type == "rules") | .data.content' "$TRANSCRIPT_PATH" 2>/dev/null | head -1)
# 2. 提取 slash_command 信息(用户通过 / 触发的 Skill)
SLASH_SKILL_META=$(jq -c 'select(.data.meta_type == "slash_command") | .data.content' "$TRANSCRIPT_PATH" 2>/dev/null | head -1)
# 3. 提取 tool_name="Skill" 的调用(Agent 主动触发的 Skill 工具调用)
# 说明:除了用户手动 /skill-name 触发外,Agent 也会自行调用 Skill 工具
AUTO_SKILL_CALLS=$(jq -c 'select(.message.content[ ]? | select(.type == "tool_use" and .name == "Skill"))' "$TRANSCRIPT_PATH" 2>/dev/null)
AUTO_SKILL_COUNT=$(printf '%s' "$AUTO_SKILL_CALLS" | grep -c . 2>/dev/null || echo 0)
AUTO_SKILL_NAMES=$(printf '%s' "$AUTO_SKILL_CALLS" | jq -r '.message.content[ ] | select(.type == "tool_use" and .name == "Skill") | .input.skill' 2>/dev/null | sort -u | jq -R -s 'split("\n") | map(select(. != ""))')
# 4. 统计全部工具调用次数
TOOL_COUNT=$(jq -c 'select(.message.content[ ]?.type == "tool_use")' "$TRANSCRIPT_PATH" 2>/dev/null | wc -l | tr -d ' ')
# 5. 记录到统计文件
STATS_DIR="$HOME/.qoder/stats"
mkdir -p "$STATS_DIR"
DATE=$(date +%Y-%m-%d)
STATS_FILE="$STATS_DIR/usage-${DATE}.jsonl"
jq -n --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg sid "$SESSION_ID" \
--argjson tc "$TOOL_COUNT" \
--argjson rules "${RULES_META:-null}" \
--argjson slash_skill "${SLASH_SKILL_META:-null}" \
--argjson auto_skill_count "$AUTO_SKILL_COUNT" \
--argjson auto_skill_names "${AUTO_SKILL_NAMES:-null}" \
'{timestamp:$ts, session_id:$sid, tool_calls:$tc, rules:$rules, slash_skill:$slash_skill, auto_skill: {count:$auto_skill_count, names:$auto_skill_names}}' >> "$STATS_FILE"
# ============================================
exit 0
```
**Transcript auto-recorded metadata includes:**
- **session\_meta(rules):** All Rules loaded in this session (name, trigger type, file path)
- **session\_meta(slash\_command):** Skills used in this session (name, type, file path)
- **session\_meta(session\_info):** Session mode (agent/plan) and type
Advanced usage:Write a periodic summary script to read `~/.qoder/stats/` JSONL files and generate Rule/Skill usage reports.
### Scenario 4: File Edit Tracking
Pain point: Unclear which files the Agent modified in a session and how many times.
Solution: Use a `PostToolUse` hook matching file-edit tools to log every file change in real time.
**Config:**
```json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|search_replace|create_file",
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/track-file-changes.sh"
}
]
}
]
}
}
```
**Script** `.qoder/hooks/track-file-changes.sh`:
```bash
#!/bin/sh
# 功能:追踪 Agent 的文件编辑操作
INPUT=$(cat)
SESSION_ID=$(printf '%s' "$INPUT" | jq -r '.session_id // empty')
TOOL_NAME=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty')
FILE_PATH="$QODER_TOOL_INPUT_FILE_PATH"
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# === 📝 文件变更追踪逻辑 ===
# 记录变更日志
CHANGE_LOG="$HOME/.qoder/stats/file-changes.jsonl"
mkdir -p "$(dirname "$CHANGE_LOG")"
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
BRANCH=$(printf '%s' "$INPUT" | jq -r '.extra.branch // empty')
REPO=$(printf '%s' "$INPUT" | jq -r '.extra.repo // empty')
echo "{\"ts\":\"$TIMESTAMP\",\"session\":\"$SESSION_ID\",\"tool\":\"$TOOL_NAME\",\"file\":\"$FILE_PATH\",\"branch\":\"$BRANCH\",\"repo\":\"$REPO\"}" >> "$CHANGE_LOG"
# ============================================
exit 0
```
**Advanced usage:**
- Use `additionalContext` to **feed change statistics back to the Agent** (e.g. "15 files modified in this session")
- Integrate with your team's code analytics system to track AI-assisted change volume
### Scenario 5: Global Usage Analytics
Pain point: No quantitative data on overall Agent usage — can't assess AI-assisted coding efficiency and quality. This includes: what questions users ask, what text the model returns, which tools are called and their results.
Solution: Use a multi-event hook combo to build full-pipeline usage data collection. `UserPromptSubmit` captures user questions, `PostToolUse` captures tool call results, `Stop` analyzes the complete session summary via Transcript (model replies, tool call distribution, etc.).
**Config:**
```json
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/usage-tracker.sh"
}
]
}
],
"PostToolUse": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/usage-tracker.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/usage-tracker.sh"
}
]
}
]
}
}
```
**Script** `~/.qoder/hooks/usage-tracker.sh`:
```bash
#!/bin/sh
# 功能:全局使用情况追踪(统一入口,按事件类型分发)
INPUT=$(cat)
EVENT=$(printf '%s' "$INPUT" | jq -r '.hook_event_name // empty')
SESSION_ID=$(printf '%s' "$INPUT" | jq -r '.session_id // empty')
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
# 获取额外上下文
EMAIL=$(printf '%s' "$INPUT" | jq -r '.extra.email // empty')
REPO=$(printf '%s' "$INPUT" | jq -r '.extra.repo // empty')
BRANCH=$(printf '%s' "$INPUT" | jq -r '.extra.branch // empty')
# === 📝 数据采集逻辑 ===
STATS_DIR="$HOME/.qoder/stats"
mkdir -p "$STATS_DIR"
DATE=$(date +%Y-%m-%d)
case "$EVENT" in
UserPromptSubmit)
# 采集用户提问内容(截取前 200 字符避免日志过大)
PROMPT=$(printf '%s' "$INPUT" | jq -r '.prompt // empty')
PROMPT_PREVIEW=$(printf '%.200s' "$PROMPT")
echo "{\"ts\":\"$TIMESTAMP\",\"event\":\"prompt\",\"session\":\"$SESSION_ID\",\"email\":\"$EMAIL\",\"repo\":\"$REPO\",\"branch\":\"$BRANCH\",\"prompt_preview\":\"$PROMPT_PREVIEW\"}" >> "$STATS_DIR/events-${DATE}.jsonl"
;;
PostToolUse)
TOOL_NAME=$(printf '%s' "$INPUT" | jq -r '.tool_name // empty')
# 采集工具调用结果(截取前 500 字符)
TOOL_RESPONSE=$(printf '%s' "$INPUT" | jq -r '.tool_response // empty')
TOOL_RESPONSE_PREVIEW=$(printf '%.500s' "$TOOL_RESPONSE")
echo "{\"ts\":\"$TIMESTAMP\",\"event\":\"tool_use\",\"session\":\"$SESSION_ID\",\"tool\":\"$TOOL_NAME\",\"repo\":\"$REPO\",\"tool_response_preview\":\"$TOOL_RESPONSE_PREVIEW\"}" >> "$STATS_DIR/events-${DATE}.jsonl"
;;
Stop)
# 📊 通过 Transcript 采集完整会话摘要
TRANSCRIPT_PATH=$(printf '%s' "$INPUT" | jq -r '.transcript_path // empty')
SUMMARY=""
if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
USER_MSG_COUNT=$(jq -c 'select(.type == "user" and (.message.content | type == "string"))' "$TRANSCRIPT_PATH" 2>/dev/null | wc -l | tr -d ' ')
USER_PROMPTS=$(jq -r 'select(.type == "user" and (.message.content | type == "string")) | .message.content' "$TRANSCRIPT_PATH" 2>/dev/null | head -20)
ASSISTANT_TEXT_COUNT=$(jq -c 'select(.type == "assistant" and (.message.content[ ]? | select(.type == "text")))' "$TRANSCRIPT_PATH" 2>/dev/null | wc -l | tr -d ' ')
ASSISTANT_TEXTS=$(jq -r 'select(.type == "assistant") | .message.content[ ]? | select(.type == "text") | .text' "$TRANSCRIPT_PATH" 2>/dev/null | head -20)
TOOL_CALL_COUNT=$(jq -c 'select(.type == "assistant") | .message.content[ ]? | select(.type == "tool_use")' "$TRANSCRIPT_PATH" 2>/dev/null | wc -l | tr -d ' ')
TOOL_NAMES=$(jq -r 'select(.type == "assistant") | .message.content[ ]? | select(.type == "tool_use") | .name' "$TRANSCRIPT_PATH" 2>/dev/null | sort | uniq -c | sort -rn | head -10)
TOOL_SUCCESS=$(jq -c 'select(.type == "user") | .message.content[ ]? | select(.type == "tool_result" and .is_error == false)' "$TRANSCRIPT_PATH" 2>/dev/null | wc -l | tr -d ' ')
TOOL_ERROR=$(jq -c 'select(.type == "user") | .message.content[ ]? | select(.type == "tool_result" and .is_error == true)' "$TRANSCRIPT_PATH" 2>/dev/null | wc -l | tr -d ' ')
SUMMARY="user_msgs:${USER_MSG_COUNT},assistant_texts:${ASSISTANT_TEXT_COUNT},tool_calls:${TOOL_CALL_COUNT},tool_success:${TOOL_SUCCESS},tool_error:${TOOL_ERROR}"
fi
echo "{\"ts\":\"$TIMESTAMP\",\"event\":\"stop\",\"session\":\"$SESSION_ID\",\"repo\":\"$REPO\",\"summary\":\"$SUMMARY\"}" >> "$STATS_DIR/events-${DATE}.jsonl"
if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
SUMMARY_DIR="$STATS_DIR/sessions"
mkdir -p "$SUMMARY_DIR"
cat < "$SUMMARY_DIR/${SESSION_ID}.json"
{
"session_id": "$SESSION_ID",
"timestamp": "$TIMESTAMP",
"repo": "$REPO",
"branch": "$BRANCH",
"email": "$EMAIL",
"user_message_count": $USER_MSG_COUNT,
"assistant_text_count": $ASSISTANT_TEXT_COUNT,
"tool_call_count": $TOOL_CALL_COUNT,
"tool_success": $TOOL_SUCCESS,
"tool_error": $TOOL_ERROR,
"tool_distribution": "$TOOL_NAMES",
"user_prompts_preview": $(printf '%s' "$USER_PROMPTS" | head -c 2000 | jq -Rs .),
"assistant_texts_preview": $(printf '%s' "$ASSISTANT_TEXTS" | head -c 2000 | jq -Rs .),
"transcript_path": "$TRANSCRIPT_PATH"
}
SUMMARY_EOF
fi
;;
esac
# ============================================
exit 0
```
**Data collection dimensions:**
| Event | Collected Data | Source |
| ------------------ | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `UserPromptSubmit` | User question (first 200 chars) | `prompt` field in stdin JSON |
| `PostToolUse` | Tool name + result (first 500 chars) | `tool_name` and `tool_response` fields in stdin JSON |
| `Stop` | Full session summary: user questions, model replies, tool call distribution, success/failure rate | JSONL file at `transcript_path` |
Why analyze via Transcript in Stop? `UserPromptSubmit` and `PostToolUse` only capture data from the current interaction, while the Transcript file at `Stop` time contains the complete session history — enabling extraction of model reply text, tool call distribution, and success/failure rates in one pass. See [Transcript File Format](#transcript-file-format) for details.
### Scenario 6: Safety Controls — Dangerous Command Blocking
Pain point: The Agent may execute `rm -rf`, `git push --force`, or other dangerous commands.
Solution: Use a `PreToolUse` hook matching `Bash|run_in_terminal` to intercept dangerous commands before execution.
**Config:**
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|run_in_terminal",
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/block-dangerous-commands.sh"
}
]
}
]
}
}
```
**Script** `.qoder/hooks/block-dangerous-commands.sh`:
```bash
#!/bin/sh
# 功能:拦截危险 Shell 命令
INPUT=$(cat)
# 提取要执行的命令(从 tool_input.command 中读取)
COMMAND=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // empty')
# === 📝 危险命令黑名单 — 请根据团队规范调整 ===
DANGEROUS_PATTERNS="rm -rf|git push --force|git push -f|DROP TABLE|DROP DATABASE|format |mkfs"
if echo "$COMMAND" | grep -qiE "$DANGEROUS_PATTERNS"; then
echo "检测到危险命令: $COMMAND" >&2
exit 2 # 阻断执行
fi
# ============================================
exit 0
```
**Key points:**
- `exit 2` immediately blocks execution; stderr content is **fed back to the Agent** as the block reason
- The Agent will **attempt an alternative** (e.g. a safer command) after being blocked
- For richer feedback, return JSON on stdout:
```json
{"hookSpecificOutput":{"permissionDecision":"deny","permissionDecisionReason":"Command contains rm -rf, blocked for safety"}}
```
### Scenario 7: Quality Gate Before Agent Completion
Pain point: The Agent claims the task is done, but tests are failing or issues remain.
Solution: Use a `Stop` hook (blockable) to run quality checks before the Agent finishes; block and force the Agent to keep working if checks fail.
**Config:**
```json
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/quality-gate.sh",
"timeout": 120
}
]
}
]
}
}
```
**Script** `.qoder/hooks/quality-gate.sh`:
```bash
#!/bin/sh
# 功能:Agent 完成前的质量门禁检查
INPUT=$(cat)
# 检查是否已经是 Stop Hook 触发的循环(防止无限循环)
STOP_HOOK_ACTIVE=$(printf '%s' "$INPUT" | jq -r '.stop_hook_active // false')
if [ "$STOP_HOOK_ACTIVE" = "true" ]; then
exit 0 # 已经是 Stop Hook 触发的重试,放行
fi
# === 📝 质量检查逻辑 — 请根据项目实际情况调整 ===
ERRORS=""
# 1. 检查是否有编译错误
# if ! make build 2>/dev/null; then
# ERRORS="${ERRORS}\n- 编译失败,请修复编译错误"
# fi
# 2. 检查是否有测试失败
# if ! make test 2>/dev/null; then
# ERRORS="${ERRORS}\n- 测试未通过,请修复失败的测试"
# fi
# 3. 检查是否有未提交的 TODO 标记
# TODO_COUNT=$(grep -r "TODO(agent)" . --include="*.go" 2>/dev/null | wc -l | tr -d ' ')
# if [ "$TODO_COUNT" -gt 0 ]; then
# ERRORS="${ERRORS}\n- 发现 $TODO_COUNT 个未完成的 TODO 标记"
# fi
# ============================================
if [ -n "$ERRORS" ]; then
cat </dev/null | wc -l | tr -d ' ')
# 2. 检查是否涉及架构设计、决策讨论、规范制定等关键词
# HAS_DECISION=$(jq -r 'select(.message.content | type == "string") | .message.content' "$TRANSCRIPT_PATH" 2>/dev/null | grep -c '架构\|方案\|规范\|最佳实践' || echo 0)
# 3. 记录会话摘要到 inbox,供后续批量复盘
SEDIMENTATION_DIR="$HOME/.ai/inbox"
mkdir -p "$SEDIMENTATION_DIR"
echo "{\"session_id\":\"$SESSION_ID\",\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"tool_calls\":$EDIT_COUNT,\"transcript\":\"$TRANSCRIPT_PATH\"}" >> "$SEDIMENTATION_DIR/pending-review.jsonl"
# 4. 可选方案 A:调用外部分析总结系统
# 通过 transcript 和会话上下文调用自己的分析服务
# curl -s -X POST http://localhost:8080/api/analyze \
# -H 'Content-Type: application/json' \
# -d "{\"session_id\":\"$SESSION_ID\",\"transcript\":\"$TRANSCRIPT_PATH\"}" \
# > /dev/null 2>&1 &
# 5. 可选方案 B:通过阻断触发分析总结 Skill
# 取消下面的注释,可让 Agent 被阻断后自动进入复盘 Skill 流程
# 注意:/retro 是自定义的沉淀复盘技能,你可以替换为自己团队的复盘 Skill。
# cat <<'EOF'
# {"decision":"block","reason":"任务已完成。检测到本次对话可能有值得沉淀的经验(文件变更较多)。请运行 /retro 进行复盘,提炼可复用的经验并沉淀到资产体系。"}
# EOF
# exit 2
# ============================================
exit 0
```
**Key points:**
- **Preventing infinite loops (mandatory):** Stop hook scripts **must check `stop_hook_active`**. When the Agent retries after being blocked by a Stop hook, this field is `true` — exit 0 immediately to avoid an infinite loop
- Use `exit 2` + `decision:"block"` to **block the Agent from completing** and force a retrospective
- `pending-review.jsonl` logs sessions for later batch review
- Can be combined with a `/retro` Skill (custom retrospective skill) to form an **auto-detect → remind → sediment** closed loop
**Current implementation options:**
Hooks currently only support `command` and `http` type handlers (no `prompt` / `agent`), so Harness self-evolution has two implementation paths: (A) call an external analysis service, or (B) block the Agent and trigger a retrospective Skill.
**Future direction:**
The hook system plans to support `prompt` type and `agent` type handlers. Once available, Harness self-evolution will upgrade from "script-driven" to "Agent-driven", enabling true end-to-end automated knowledge sedimentation.
### Scenario 9: Auto-Lint After File Writes
Automatically run a linter every time the Agent writes or edits a file.
Script `${project}/.qoder/hooks/auto-lint.sh`:
```bash
#!/bin/bash
input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path')
# Only lint JS/TS files
case "$file_path" in
*.js|*.ts|*.jsx|*.tsx)
npx eslint "$file_path" --fix 2>/dev/null
;;
esac
exit 0
```
Config: event `PostToolUse`, matcher `Write|Edit`, command `.qoder/hooks/auto-lint.sh`.
### Scenario 10: Log Tool Failures
Write to a log file whenever one of the Agent's tool calls fails, making it easier to troubleshoot.
Script `~/.qoder/hooks/log-failure.sh`:
```bash
#!/bin/bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.tool_name')
error=$(echo "$input" | jq -r '.error')
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] $tool_name failed: $error" >> ~/.qoder/hooks/failure.log
exit 0
```
Config: event `PostToolUseFailure`, no matcher (matches all tools), command `~/.qoder/hooks/log-failure.sh`.
### Scenario 11: Desktop Notification on Completion
Show a system notification when the Agent finishes a task. Great for long-running tasks.
Script `~/.qoder/hooks/notify-done.sh` (macOS):
```bash
#!/bin/bash
input=$(cat)
message=$(echo "$input" | jq -r '.last_assistant_message // "Task complete"' | head -c 100)
osascript -e "display notification \"$message\" with title \"Qoder IDE Agent\""
exit 0
```
Config: event `Stop`, no matcher, command `~/.qoder/hooks/notify-done.sh`.
## Transcript File Format
The Transcript is a **session log file** automatically generated by Qoder IDE, located at the path pointed to by `transcript_path` (e.g. `~/.qoder/projects//transcript/.jsonl`). Each line is an independent JSON object appended in chronological order, recording the complete session interaction.
### Common Fields Per Line
| Field | Type | Description |
| ----------- | ------ | --------------------------------------------------------------- |
| `type` | string | Record type: `session_meta` / `user` / `assistant` / `progress` |
| `sessionId` | string | Session ID |
| `uuid` | string | Unique ID for this record |
| `timestamp` | string | ISO 8601 timestamp |
| `cwd` | string | Current working directory |
| `message` | object | Message content (present for `user`/`assistant` types) |
| `data` | object | Metadata (present for `session_meta`/`progress` types) |
### Record Types
**1. `session_meta` — Session metadata (first line)**
The first line of every Transcript file records the session's basic information:
```json
{
"type": "session_meta",
"sessionId": "86379a0e-...",
"data": {
"meta_type": "session_info",
"content": {
"mode": "agent",
"session_type": "assistant"
}
}
}
```
- `data.content.mode`: Session mode (`agent` / `plan` / `ask` / `debug`)
- `data.content.session_type`: Session type (`assistant` / `inline_chat`, etc.)
**2. `user` — User messages**
User messages come in two forms:
**User question** (`message.content` is a string):
```json
{
"type": "user",
"message": {
"role": "user",
"content": "Delete comments from test.py"
}
}
```
**Tool result** (`message.content` is an array containing `tool_result`):
```json
{
"type": "user",
"message": {
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "call_d498c5988a...",
"content": "Contents of /path/to/file.py, from line 1-23 ...",
"is_error": false
}
]
},
"toolUseResult": "Contents of /path/to/file.py ..."
}
```
- `is_error`: Whether the tool execution failed
- `toolUseResult`: Shortcut field for the tool result (same as `content[0].content`)
**3. `assistant` — Model replies**
Model reply `message.content` is always an array containing two element types:
**Text reply** (`type: "text"`):
```json
{
"type": "assistant",
"message": {
"role": "assistant",
"content": [
{
"type": "text",
"text": "I'll help you delete comments from test.py. Let me read the file first.\n\n"
}
]
}
}
```
**Tool call** (`type: "tool_use"`):
```json
{
"type": "assistant",
"message": {
"role": "assistant",
"content": [
{
"type": "tool_use",
"id": "call_d498c5988a...",
"name": "read_file",
"input": {
"file_path": "/path/to/file.py"
}
}
]
}
}
```
- `name`: Tool name (e.g. `read_file`, `search_replace`, `run_in_terminal`, `Skill`)
- `input`: Tool call parameters
- `id`: Corresponds to `tool_use_id` in the subsequent `tool_result`
**4. `progress` — Hook trigger records**
Records when hook scripts fire and which commands run:
```json
{
"type": "progress",
"data": {
"type": "hook_progress",
"hookEvent": "UserPromptSubmit",
"hookName": "UserPromptSubmit",
"command": ".qoder/hooks/inject-skill-hint.sh"
}
}
```
### Session Timeline Example
A typical session's Transcript record order:
```plaintext
L1 session_meta ← Session start, record mode and type
L2 progress ← UserPromptSubmit Hook fires
L3 user (string) ← User question: "Delete comments from test.py"
L4 assistant (text) ← Model reply: "I'll help you..."
L5 assistant (tool_use) ← Model calls read_file
L6 user (tool_result) ← read_file returns file content
L7 assistant (text) ← Model reply: "Now I'll delete..."
L8 assistant (tool_use) ← Model calls search_replace
L9 user (tool_result) ← search_replace succeeds
L10 assistant (text) ← Model reply: "Successfully deleted..."
L11 progress ← Stop Hook fires
L12 assistant (text) ← Final reply after Stop Hook
```
### Common jq Extraction Commands
```bash
TRANSCRIPT="$TRANSCRIPT_PATH"
# Extract all user questions (filter out tool results)
jq -r 'select(.type == "user" and (.message.content | type == "string")) | .message.content' "$TRANSCRIPT"
# Extract all model text replies
jq -r 'select(.type == "assistant") | .message.content[ ]? | select(.type == "text") | .text' "$TRANSCRIPT"
# Extract all tool calls (tool name + parameters)
jq -c 'select(.type == "assistant") | .message.content[ ]? | select(.type == "tool_use") | {name, input}' "$TRANSCRIPT"
# Count tool call distribution (tool name + count)
jq -r 'select(.type == "assistant") | .message.content[ ]? | select(.type == "tool_use") | .name' "$TRANSCRIPT" | sort | uniq -c | sort -rn
# Extract failed tool calls
jq -c 'select(.type == "user") | .message.content[ ]? | select(.type == "tool_result" and .is_error == true)' "$TRANSCRIPT"
# Get session mode
jq -r 'select(.type == "session_meta") | .data.content.mode' "$TRANSCRIPT"
# Get Hook trigger records
jq -c 'select(.type == "progress" and .data.type == "hook_progress") | {event: .data.hookEvent, command: .data.command}' "$TRANSCRIPT"
```
## Design Principles
| Principle | Description |
| ------------------------- | --------------------------------------------------------------------------------- |
| **Fail fast** | Hook scripts should be lightweight to avoid blocking the Agent's main flow |
| **Graceful degradation** | Abnormal exit codes (not 0 or 2) do not block the Agent, ensuring fault tolerance |
| **Single responsibility** | Each script does one thing; combine multiple hooks for complex logic |
| **Idempotent design** | The same event may fire multiple times; scripts should be idempotent |
| **Loop prevention** | Stop hooks must check `stop_hook_active` to prevent infinite retries |
### Recommended Hook Combinations
| Goal | Recommended Combination |
| -------------------------- | ------------------------------------------------------------------------ |
| **Safety controls** | `PreToolUse(Bash)` dangerous command blocking |
| **Quality assurance** | `Stop` quality gate |
| **Data-driven insights** | `UserPromptSubmit` + `PostToolUse` + `Stop` full-pipeline collection |
| **Harness self-evolution** | `Stop` sedimentation detection + `UserPromptSubmit` Skill guidance |
| **Team collaboration** | Project-level `.qoder/settings.json` with unified config, shared via Git |
## Debugging Guide
### Step 1: Confirm the Hook Fires
When a hook **does not fire as expected**, add debug logging at the **very start** of the script:
```bash
#!/bin/sh
# ===== Debug mode: confirm hook fires =====
INPUT=$(cat)
printf '[HOOK DEBUG] %s hook triggered, event=%s\n' "$(date '+%H:%M:%S')" "$(printf '%s' "$INPUT" | jq -r '.hook_event_name')" >> /tmp/hook-debug.log
printf '%s' "$INPUT" | jq . >> /tmp/hook-debug.log
echo "---" >> /tmp/hook-debug.log
# ===== Remove debug code when done =====
# ... your actual logic ...
exit 0
```
Then trigger an Agent operation and check the log:
```bash
$ tail -f /tmp/hook-debug.log
[HOOK DEBUG] 14:32:01 hook triggered, event=PreToolUse
{
"session_id": "abc123",
"hook_event_name": "PreToolUse",
"tool_name": "run_in_terminal",
"tool_input": {
"command": "ls -la"
},
...
}
```
Troubleshooting:If no output appears, the hook is not firing. Check your config file location, event name, matcher pattern, and script path.
### Step 2: Reproduce Locally with Real Input
Use the JSON captured in Step 1 to test the script **outside of Qoder IDE**:
```bash
# Pipe the captured input to simulate stdin
$ cat /tmp/hook-debug.json | sh .qoder/hooks/pre-tool-check.sh
$ echo $? # Check exit code: 0=allow, 2=block
# Or manually construct test input
$ echo '{"hook_event_name":"PreToolUse","tool_name":"run_in_terminal","tool_input":{"command":"rm -rf /"}}' | sh .qoder/hooks/pre-tool-check.sh
$ echo $? # Expected: 2 (block dangerous command)
```
Tip:Save common test cases as files for repeated validation.
### Step 3: Other Debugging Methods
1. **Check the Transcript:** `~/.qoder/projects//transcript/.jsonl` — parse with `jq` line by line
2. **Check Hook logs:** Search for `[hook]` prefix in Qoder IDE logs for execution results and timing
3. **Start simple:** First verify the hook fires with a bare `exit 0`, then add business logic incrementally
4. **Clean up:** Remove debug code (`/tmp/hook-debug.log` writes) after debugging to avoid performance impact
## Quick Start Template
### Minimal Config
Save the following to `~/.qoder/settings.json` (user-level) or `/.qoder/settings.json` (project-level):
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/pre-tool-check.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/post-edit-track.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/on-stop.sh"
}
]
}
]
}
}
```
### Project Directory Structure
```plaintext
/
├── .qoder/
│ ├── settings.json ← Hook config (Git-shared)
│ ├── settings.local.json ← Local override config (.gitignore)
│ └── hooks/ ← Hook scripts directory
│ ├── pre-tool-check.sh
│ ├── post-edit-track.sh
│ └── on-stop.sh
└── ...
```
### Full Config Example
Here is a complete configuration with hooks for five commonly used events:
```json
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/check-prompt.sh"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/block-dangerous.sh"
}
]
},
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/validate-file-path.sh"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": ".qoder/hooks/auto-lint.sh"
}
]
}
],
"PostToolUseFailure": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/log-failure.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/notify-done.sh"
}
]
}
]
}
}
```
# Deeplinks
Deeplinks are a navigation mechanism based on a custom URL that allows you to launch Qoder IDE directly from a browser, documentation, terminal, or other external environment—opening a specific page or performing a specific action such as starting a chat, creating a Quest task, importing a rule, or adding an MCP service configuration.
For Deeplinks that involve writing content or importing configurations, Qoder IDE will display a confirmation dialog for you to review before proceeding. Some Deeplinks also require you to be logged in first.

## URL Format
```
{scheme}://{host}/{path}?{parameters}
```
| Component | Description | Example |
| ------------ | ---------------------------- | -------------------------------------------------- |
| `scheme` | Protocol | `qoder` |
| `host` | Deeplinks handler identifier | `aicoding.aicoding-deeplink` |
| `path` | Action path | `/chat`, `/quest`, `/rule`, `/command`, `/mcp/add` |
| `parameters` | URL query parameters | `text=hello&mode=agent` |
## Available Deeplink Types
| Path | Description | Login Required |
| ---------- | --------------------- | -------------- |
| `/chat` | Create Chat | Yes |
| `/quest` | Create Quest task | Yes |
| `/rule` | Create rule | No |
| `/command` | Create custom command | No |
| `/mcp/add` | Add MCP service | No |
## Create Chat /chat
Open a chat session directly via a link. When opening the link, Qoder IDE will first show the content to be brought into the new conversation. After confirmation, it will create a new chat and pre-fill the text into the input box without sending it automatically. You must be logged in before using it.
### URL Format
```
qoder://aicoding.aicoding-deeplink/chat?text={prompt}&mode={mode}&isNewChat={isNewChat}
```
### Parameters
| Parameter | Required | Description |
| ----------- | -------- | ---------------------------------------------------------------------------------------------------- |
| `text` | Yes | The prompt content to pre-fill |
| `mode` | No | Chat mode: `agent`, `ask`, `chat`, or `experts` when Experts is enabled. `ask` is handled as `chat`. |
| `isNewChat` | No | Whether to create a new chat. Defaults to `true`; set to `false` to pre-fill the current chat. |
### Example
```
qoder://aicoding.aicoding-deeplink/chat?text=Help%20me%20refactor%20this%20code&mode=agent
```
### Generate Link Code
```typescript
function generateChatDeeplink(text: string, mode?: 'agent' | 'ask' | 'chat' | 'experts', isNewChat?: boolean): string {
if (!text) {
throw new Error('Missing required parameter: text');
}
const url = new URL('qoder://aicoding.aicoding-deeplink/chat');
url.searchParams.set('text', text);
if (mode) {
url.searchParams.set('mode', mode);
}
if (isNewChat !== undefined) {
url.searchParams.set('isNewChat', String(isNewChat));
}
return url.toString();
}
// Example
const deeplink = generateChatDeeplink('Help me refactor this code', 'agent');
console.log(deeplink);
// qoder://aicoding.aicoding-deeplink/chat?text=Help+me+refactor+this+code&mode=agent
```
```python
from urllib.parse import urlencode
def generate_chat_deeplink(text: str, mode: str = None, is_new_chat: bool = None) -> str:
if not text:
raise ValueError('Missing required parameter: text')
params = {'text': text}
if mode:
params['mode'] = mode
if is_new_chat is not None:
params['isNewChat'] = str(is_new_chat).lower()
return f"qoder://aicoding.aicoding-deeplink/chat?{urlencode(params)}"
# Example
deeplink = generate_chat_deeplink('Help me refactor this code', 'agent')
print(deeplink)
```
## Create Quest Task /quest
Open or focus the independent Quest window and pre-fill a new Quest draft. When opening the link, you can review the task description and execution mode before deciding whether to proceed. You must be logged in before using it.
### URL Format
```
qoder://aicoding.aicoding-deeplink/quest?text={description}&agentClass={agentClass}
```
### Parameters
| Parameter | Required | Description |
| ------------ | -------- | --------------------------------------------------------- |
| `text` | Yes | Task description |
| `agentClass` | No | Execution mode: `LocalAgent` (default) or `LocalWorktree` |
#### Execution Modes
| Mode | Description |
| --------------- | -------------------------------- |
| `LocalAgent` | Execute in current workspace |
| `LocalWorktree` | Execute in isolated git worktree |
### Example
```
qoder://aicoding.aicoding-deeplink/quest?text=Implement%20user%20authentication%20with%20JWT&agentClass=LocalWorktree
```
### Generate Link Code
```typescript
type AgentClass = 'LocalAgent' | 'LocalWorktree';
function generateQuestDeeplink(text: string, agentClass?: AgentClass): string {
if (!text) {
throw new Error('Missing required parameter: text');
}
const url = new URL('qoder://aicoding.aicoding-deeplink/quest');
url.searchParams.set('text', text);
if (agentClass) {
url.searchParams.set('agentClass', agentClass);
}
return url.toString();
}
// Example
const deeplink = generateQuestDeeplink('Implement user authentication with JWT', 'LocalWorktree');
console.log(deeplink);
```
```python
from urllib.parse import urlencode
def generate_quest_deeplink(text: str, agent_class: str = None) -> str:
if not text:
raise ValueError('Missing required parameter: text')
params = {'text': text}
if agent_class:
params['agentClass'] = agent_class
return f"qoder://aicoding.aicoding-deeplink/quest?{urlencode(params)}"
# Example
deeplink = generate_quest_deeplink('Implement user authentication with JWT', 'LocalWorktree')
print(deeplink)
```
## Create Rule /rule
Import rules to guide AI behavior via a link. Rules can define coding standards, project conventions, or specific instructions for AI responses. When opening the link, you can first review the rule name and content before deciding whether to import it; upon confirmation, the corresponding rule will be created.
### URL Format
```
qoder://aicoding.aicoding-deeplink/rule?name={ruleName}&text={ruleContent}
```
### Parameters
| Parameter | Required | Description |
| --------- | -------- | ---------------------------- |
| `name` | Yes | Rule name (used as filename) |
| `text` | Yes | Rule content |
### Example
```
qoder://aicoding.aicoding-deeplink/rule?name=typescript-conventions&text=Always%20use%20strict%20TypeScript%20types
```
### Generate Link Code
```typescript
function generateRuleDeeplink(name: string, text: string): string {
if (!name || !text) {
throw new Error('Missing required parameters: name and text');
}
const url = new URL('qoder://aicoding.aicoding-deeplink/rule');
url.searchParams.set('name', name);
url.searchParams.set('text', text);
return url.toString();
}
// Example
const deeplink = generateRuleDeeplink(
'typescript-conventions',
`Always use strict TypeScript types.
Avoid using 'any' type.
Prefer interfaces over type aliases for object shapes.`
);
console.log(deeplink);
```
```python
from urllib.parse import urlencode
def generate_rule_deeplink(name: str, text: str) -> str:
if not name or not text:
raise ValueError('Missing required parameters: name and text')
params = {'name': name, 'text': text}
return f"qoder://aicoding.aicoding-deeplink/rule?{urlencode(params)}"
# Example
deeplink = generate_rule_deeplink(
'typescript-conventions',
"""Always use strict TypeScript types.
Avoid using 'any' type.
Prefer interfaces over type aliases for object shapes."""
)
print(deeplink)
```
## Add MCP Service /mcp/add
Quickly add MCP (Model Context Protocol) service configurations via a link. MCP services extend AI capabilities by providing additional tools and context sources. When opening the link, Qoder IDE will first display the service information to be added and open the MCP settings page, allowing you to review and confirm simultaneously.
### URL Format
```
qoder://aicoding.aicoding-deeplink/mcp/add?name={serverName}&config={base64EncodedConfig}
```
### Parameters
| Parameter | Required | Description |
| --------- | -------- | --------------------------------------------- |
| `name` | Yes | MCP service name |
| `config` | Yes | Base64 encoded MCP service JSON configuration |
> Note: The configuration must contain either `command` or `url`; if the name already exists, it cannot be added again.
### Example
```
qoder://aicoding.aicoding-deeplink/mcp/add?name=postgres&config=JTdCJTIyY29tbWFuZCUyMiUzQSUyMm5weCUyMiUyQyUyMmFyZ3MlMjIlM0ElNUIlMjIteSUyMiUyQyUyMiU0MG1vZGVsY29udGV4dHByb3RvY29sJTJGc2VydmVyLXBvc3RncmVzJTIyJTJDJTIycG9zdGdyZXNxbCUzQSUyRiUyRmxvY2FsaG9zdCUyRm15ZGIlMjIlNUQlN0Q%3D
```
### Generate Link Code
MCP service JSON configuration encoding Process:
1. Create the configuration JSON object
2. Serialize with `JSON.stringify()`
3. URL encode with `encodeURIComponent()`
4. Base64 encode with `btoa()`
5. URL encode the result with `encodeURIComponent()`
```typescript
interface McpServerConfig {
command?: string;
args?: string[];
url?: string;
env?: Record;
}
function generateMcpAddDeeplink(name: string, config: McpServerConfig): string {
if (!name) {
throw new Error('Missing required parameter: name');
}
if (!config) {
throw new Error('Missing required parameter: config');
}
if (!config.command && !config.url) {
throw new Error('Config must contain either "command" or "url"');
}
const configJson = JSON.stringify(config);
const base64Config = btoa(encodeURIComponent(configJson));
const encodedName = encodeURIComponent(name);
const encodedConfig = encodeURIComponent(base64Config);
return `qoder://aicoding.aicoding-deeplink/mcp/add?name=${encodedName}&config=${encodedConfig}`;
}
// Example 1: PostgreSQL MCP Server
const postgresDeeplink = generateMcpAddDeeplink('postgres', {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-postgres', 'postgresql://localhost/mydb']
});
console.log(postgresDeeplink);
// Example 2: GitHub MCP Server with environment variables
const githubDeeplink = generateMcpAddDeeplink('github', {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-github'],
env: { GITHUB_PERSONAL_ACCESS_TOKEN: '' }
});
console.log(githubDeeplink);
// Example 3: HTTP-based MCP Server
const httpDeeplink = generateMcpAddDeeplink('custom-server', {
url: 'https://mcp.example.com/sse'
});
console.log(httpDeeplink);
```
```python
import json
import base64
from urllib.parse import quote
def generate_mcp_add_deeplink(name: str, config: dict) -> str:
if not name:
raise ValueError('Missing required parameter: name')
if not config:
raise ValueError('Missing required parameter: config')
if 'command' not in config and 'url' not in config:
raise ValueError('Config must contain either "command" or "url"')
config_json = json.dumps(config)
config_encoded = quote(config_json)
config_base64 = base64.b64encode(config_encoded.encode()).decode()
encoded_name = quote(name)
encoded_config = quote(config_base64)
return f"qoder://aicoding.aicoding-deeplink/mcp/add?name={encoded_name}&config={encoded_config}"
# Example 1: PostgreSQL MCP Server
postgres_deeplink = generate_mcp_add_deeplink('postgres', {
'command': 'npx',
'args': ['-y', '@modelcontextprotocol/server-postgres', 'postgresql://localhost/mydb']
})
print(postgres_deeplink)
# Example 2: GitHub MCP Server with environment variables
github_deeplink = generate_mcp_add_deeplink('github', {
'command': 'npx',
'args': ['-y', '@modelcontextprotocol/server-github'],
'env': { 'GITHUB_PERSONAL_ACCESS_TOKEN': '' }
})
print(github_deeplink)
```
## Create Command /command
Quickly create custom commands via links, ideal for distributing common prompt templates, project operation guides, or team-agreed commands. When opening the link, Qoder IDE will first display the command name, scope, description, and content before creating it upon confirmation.
### URL Format
```
qoder://aicoding.aicoding-deeplink/command?name={name}&text={content}&description={description}&scope={scope}
```
### Parameters
| Parameter | Required | Description |
| ------------- | -------- | ------------------------------------------------------------------------------------ |
| `name` | Yes | Command name, must only contain lowercase letters, numbers, hyphens, and underscores |
| `text` | Yes | Command content |
| `description` | No | Command description |
| `scope` | No | Scope: `user` or `project`, default is `user` |
#### Scope
| Scope | Description |
| --------- | -------------------------------------------------------- |
| `user` | Adds only to the current user environment |
| `project` | Adds to the current workspace, suitable for team sharing |
### Example
```
qoder://aicoding.aicoding-deeplink/command?name=review_pr&text=Please%20help%20me%20review%20this%20PR&description=Review%20pull%20request&scope=user
```
### Generate Link Code
```typescript
type CommandScope = 'user' | 'project';
function generateCommandDeeplink(
name: string,
text: string,
description?: string,
scope: CommandScope = 'user'
): string {
if (!name) {
throw new Error('Missing required parameter: name');
}
if (!text) {
throw new Error('Missing required parameter: text');
}
if (!/^[a-z0-9_-]+$/.test(name)) {
throw new Error('Command name can only contain lowercase letters, numbers, hyphens and underscores');
}
const url = new URL('qoder://aicoding.aicoding-deeplink/command');
url.searchParams.set('name', name);
url.searchParams.set('text', text);
if (description) {
url.searchParams.set('description', description);
}
url.searchParams.set('scope', scope);
return url.toString();
}
// Example
const deeplink = generateCommandDeeplink(
'review_pr',
'Please help me review this PR',
'Review pull request'
);
console.log(deeplink);
```
```python
import re
from urllib.parse import urlencode
def generate_command_deeplink(name: str, text: str, description: str = None, scope: str = 'user') -> str:
if not name:
raise ValueError('Missing required parameter: name')
if not text:
raise ValueError('Missing required parameter: text')
if not re.match(r'^[a-z0-9_-]+$', name):
raise ValueError('Command name can only contain lowercase letters, numbers, hyphens and underscores')
if scope not in ('user', 'project'):
raise ValueError('Invalid scope value. Valid values are: user, project')
params = {
'name': name,
'text': text,
'scope': scope,
}
if description:
params['description'] = description
return f"qoder://aicoding.aicoding-deeplink/command?{urlencode(params)}"
# Example
deeplink = generate_command_deeplink('review_pr', 'Please help me review this PR', 'Review pull request')
print(deeplink)
```
### Usage Notes
1. After clicking the link, Qoder IDE will first display the command information for your confirmation.
2. `name` cannot be empty and can only use lowercase letters, numbers, hyphens, and underscores.
3. `scope=project` requires you to have a workspace currently open; otherwise, it cannot be created.
4. Commands with the same name cannot be created repeatedly.
## Security Considerations
> **Important**: Always review Deeplinks content before clicking.
- **Never include sensitive data**: Do not embed API keys, passwords, or proprietary code in Deeplinks
- **Verify the source**: Only click Deeplinks from trusted sources
- **Review before confirming**: Qoder IDE always shows a confirmation dialog - carefully review the content before proceeding
- **No automatic execution**: Deeplinks never execute automatically; user confirmation is always required
## Troubleshooting
| Issue | Possible Cause | Solution |
| ------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------ |
| "Unregistered deeplink path" | Unsupported deeplink path | Check if the path is supported and ensure Qoder IDE version is 0.2.21 or above |
| "Missing required parameter" | Parameter not provided | Check that all required parameters are included in the URL |
| "Invalid JSON config" | Malformed JSON | Validate JSON structure before encoding |
| "Quest Mode is disabled" | Quest feature not enabled | Enable Quest Mode in Settings |
| Login prompt appears | Deeplink requires authentication | Sign in to your account first |
| "Invalid Base64 encoded config" | Incorrect MCP config encoding | Ensure correct encoding order: JSON → encodeURIComponent → btoa → encodeURIComponent |
## URL Length Limits
Deeplink URLs should not exceed **8,000 characters**. For longer content, consider:
- Shortening the prompt or rule content
- Using external references instead of inline content
- Splitting into multiple deeplinks
# Canvas
> Render text, data, or analysis into a laid-out visual panel — annotate directly on the canvas and share it with your team in one click.
Canvas lets the Agent turn text, data, or analysis into a laid-out panel with stat cards, tables, charts, and more. You can annotate directly on the canvas to collaborate on changes, and share it with your team in one click.
## What Canvas is
- **A visual view of the Agent's output** — chunky text becomes a paneled layout that's easier to scan.
- **A standard `.canvas.tsx` file** — the Agent generates or edits this file, and every change is reflected live in the Canvas preview.
- **Prompt-driven edits** — no need to hand-edit the source; describe the change you want in chat and the Agent updates the source and re-renders automatically.
## Use cases
- **Dashboards** — after the Agent analyzes logs or metrics, it builds a dashboard in Canvas with KPIs and trend charts at a glance.
- **Structured reports** — turn dense findings (profiling, dependency analysis, and the like) into sectioned panels instead of walls of text.
- **Architecture and flow visualization** — when clarifying system behavior or writing docs, render state flows, module dependencies, or high-level architecture so the team stays aligned.
## How to use
Trigger Canvas with the `/canvas` command in chat:
- **First render**: describe what you want on the canvas. The Agent creates the `.canvas.tsx` file and renders it in the Canvas preview.
- **Iterate**: keep prompting the Agent in the same conversation, or annotate directly on the Canvas — the Agent updates the source and re-renders.
## Annotation
Annotation lets you point directly at what needs adjusting on the Canvas so the Agent understands your feedback more precisely — pointing at a legend is faster and less ambiguous than describing "the legend on the third chart" in words.
**How to use:**
- **Enter annotation mode**: click the annotation entry on the Canvas.
- **Select or circle a target**: click a specific element, or draw a freehand circle around a region.
- **Add a comment**: type your suggested changes or feedback on the annotation.
- **Send to the Agent**: the annotation is attached to the conversation as context; the Agent reads it, updates the Canvas source, and re-renders.
## Sharing
Canvas supports one-click publishing so you can share a canvas with your teammates. Published canvases are **visible only within your organization** — they are not exposed publicly.
Sharing is available on **Teams / Enterprise** plans only. Personal-plan users will see: *"Sharing is available on Teams and Enterprise plans. Join or create a team to share."*
### Publish a Canvas
Click **Publish** in the Canvas toolbar to publish the current canvas to your organization.
- The publish popover shows *"All team members can view"* — confirm to complete publishing.
- The button then changes to **Published**, and teammates can open the canvas from the share link within your organization.
### After publishing
Click **Published** to open a dropdown menu:
| Action | Description |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sync** | Sync the latest Canvas content to the published version. Shows a loading state while syncing; on success the timestamp updates to "Last synced just now". |
| **Copy link** | Copy the share link to the clipboard so you can hand it to teammates. |
| **Unpublish** | Revoke sharing. The original link stops working and the button reverts to **Publish**. |
| **View published Canvas** | Open the enterprise admin console's shared list. |
The menu also shows the last sync time, e.g. `Last synced 5 minutes ago`.
### My Shares
**My Shares** in the left navigation of the enterprise admin console collects everything you've shared from Qoder IDE (currently just Canvas).
- **Entry**: Enterprise admin console → **My Shares** (hidden when you have no shared content).
- **Columns**: Canvas name, publish / last synced time.
- **Row actions**:
- Click a Canvas name — preview the published canvas.
- `...` menu on the right — **Copy link**, **Delete** (deletes canvases you published).
## Package as Skill
If you frequently generate canvases with a similar structure, you can package the entire workflow as a Skill and reproduce the same canvas with a simple trigger.
A Canvas Skill typically includes:
- **Trigger description** — defines the scenario that invokes the Skill, e.g. "generate this week's deploy dashboard" or "incident postmortem panel."
- **Layout specifications** — specifies the panel structure, card types, and chart styles.
- **Data sources** — the fetching logic the Agent runs during generation, such as database queries, API requests, or log analysis scripts.
- **Formatting conventions** — standardizes number precision, time formats, color coding, and other display rules.
Once packaged, anyone on the team can use a short prompt to have the Agent pull the latest data and regenerate the canvas, keeping the output structure consistent.
# Commands
## Custom Commands
The Custom Commands feature allows you to encapsulate frequently used prompts and workflows into reusable commands. Simply type `/` in the Agent dialog to quickly invoke these commands, significantly improving your daily development efficiency.
Whether you frequently perform code reviews, generate test cases, or need quick access to project specifications, custom commands can simplify repetitive operations into "one-click" tasks.
### Command Types and Scope
| Feature | User Commands | Project Commands |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| **Scope** | Applies to all projects for the current user | Only effective in the current project root directory and its subdirectories |
| **Storage Path** | - macOS / Linux: `/home//.qoder/commands/` or `/Users//.qoder/commands/` - Windows: `C:\Users\\.qoder\commands\` | `/.qoder/commands/` |
| **Directory Organization** | Supports categorization by folders under the `commands` directory | Supports categorization by folders under the `commands` directory |
| **Use Cases** | General development tasks, such as: • Code review • Generate unit tests | Project-specific tasks, such as: • Check project API specifications • Validate configuration file format |
| **Sharing** | Limited to current user only | Can be shared with team members via Git or other version control systems |
> **Note**: User-level commands do not support cross-device synchronization. You can manually migrate configuration files.
>
> **Note**: Before creating a project-level command, please open the target project first; if user-level and project-level commands with the same name exist simultaneously, a scope indicator will be attached in the list for easy distinction.
### Creating Custom Commands
1. **Open the Command Management Interface**
- Method 1: Go to the Commands page in Qoder IDE Settings and click the **"Add"** button
- Method 2: Type `/` in the dialog and click the **"Add Command"** shortcut at the bottom (if available)
2. Enter a **unique command name** (e.g., `gen-test`) in the top search bar, then press **Enter**.
3. Command name rules:
- Only lowercase letters, numbers, hyphens (`-`), and underscores (`_`) are supported
- Name cannot be empty
- Recommended length is under 100 characters
- Cannot duplicate an existing command name within the same scope
4. Select the command type:
- **User-level**: Universal commands applicable to all projects
- **Project-level**: Only available in the current project; cannot be created if no project is open
5. Fill in the command description and body content in the editing area. It's recommended to start with a brief description of its purpose, followed by the complete prompt or steps in the body.
6. After saving, return to the conversation and type `/` in the dialog to see the newly created command.
> **Note**: If the command body is empty or only retains the default placeholder content, the command will not appear in the available list.
### Command Updates and List Refresh
When you add, modify, or delete command files, the command list will refresh to the latest state, allowing you to seamlessly continue using the latest version in your conversation.
Common refresh scenarios include:
- After adding a command, a new option will appear in the list
- After modifying command content, subsequent selections will use the updated content
- After deleting a command, the corresponding item will disappear from the list
If you maintain many commands simultaneously, it is recommended to:
- Place commands into different subdirectories by purpose for easier organization
- Provide clear descriptions for commands to facilitate searching and identification in the list
- Regularly clean up old, unused commands to reduce duplication and confusion
### Example Commands
```
## Overview
Execute project test suite and resolve detected issues through systematic troubleshooting and verification.
## Testing Phases
1. **Environment Setup**
- Verify development environment
- Check dependencies status
- Confirm test data availability
- Validate configuration settings
2. **Test Execution**
- Run unit test suite
- Execute integration tests
- Perform smoke tests
- Check code coverage
3. **Issue Resolution**
- Document test failures
- Analyze error patterns
- Debug failed cases
- Implement fixes
## Validation Matrix
### Core Tests
- [ ] Unit test completion
- [ ] API test verification
- [ ] Database test results
- [ ] Cache behavior check
### System Health
- [ ] Memory usage normal
- [ ] Response times acceptable
- [ ] Error rates within limits
- [ ] Resource utilization stable
## Resolution Flow
1. **Fix Implementation**
- Address critical issues first
- Apply necessary patches
- Update test cases
- Document changes
```
→ Try in Qoder IDE
```
## Overview
Create and save a structured markdown file (agents.md) that defines AI agent specifications for model comprehension.
## Generation Workflow
1. **File Creation**
- Set file path: ./docs/agents.md
- Create directory if not exists
- Initialize markdown file
- Set file permissions
2. **Content Generation**
- Write file header
- Generate metadata section
- Create main content blocks
- Add version control info
3. **Document Structure**
- Define agent identity
- List capabilities and limits
- Specify interaction rules
- Document dependencies
## File Components
### Required Sections
- [ ] File metadata
- [ ] Agent definition
- [ ] Capability matrix
- [ ] Interaction protocols
- [ ] Version information
### File Operations
- [ ] Directory check
- [ ] File creation
- [ ] Content writing
- [ ] Permission setting
## Validation Steps
1. **File Verification**
- Check file existence
- Validate markdown syntax
- Verify content structure
- Confirm file accessibility
```
→ Try in Qoder IDE
# Keyboard Shortcuts
Qoder IDE allows you to use keyboard shortcuts to streamline your workflow, including features like inline chat and diff navigation.
Below is a comprehensive list of default shortcuts grouped by functionality.
## **General**
| **Command** | **macOS** | **Windows** |
| :---------------------- | :-------- | :------------- |
| Open/Close Chat | `⌘ L` | `Ctrl L` |
| Open Settings | `⌘ ,` | `Ctrl ,` |
| Open Qoder IDE Settings | `⌘ ⇧ ,` | `Ctrl Shift ,` |
| Open command palette | `⌘ ⇧ P` | `Ctrl Shift P` |
## **Chat**
| **Command** | **macOS** | **Windows** |
| :--------------------------- | :-------- | :--------------- |
| Submit a message | `⏎` | `⏎` |
| Insert a new line in input | `⇧ ⏎` | `Shift ⏎` |
| Accept all suggested changes | `⌘ ⏎` | `Ctrl ⏎` |
| Reject all suggested changes | `⌘ ⌫` | `Ctrl Backspace` |
## **Inline Chat**
| **Command** | **macOS** | **Windows** |
| :------------------ | :-------- | :---------- |
| Open an inline chat | `⌘ I` | `Ctrl I` |
| Send to chat | `⌘ L` | `Ctrl L` |
## **Code Selection and Context**
| **Command** | **macOS** | **Windows** |
| :-------------------------------- | :-------- | :---------- |
| Add context to chat | `#` | `#` |
| Invoke shortcut commands | `/` | `/` |
| Add the current selection to chat | `⌘ L` | `Ctrl L` |
## **Diff View**
| **Command** | **macOS** | **Windows** |
| :------------------------------ | :-------- | :--------------------- |
| Accept a single change | `⌘ ⇧ ⏎` | `Ctrl Shift ⏎` |
| Reject a single change | `⌘ ⇧ ⌫` | `Ctrl Shift Backspace` |
| Accept all changes in file | `⌘ ⏎` | `Ctrl ⏎` |
| Reject all changes in file | `⌘ ⌫` | `Ctrl Backspace` |
| Navigate to the next file | `⌘ ⇧ [` | `Ctrl Shift [` |
| Navigate to the previous file | `⌘ ⇧ ]` | `Ctrl Shift ]` |
| Navigate to the next change | `⌥ J` | `Alt` `J` |
| Navigate to the previous change | `⌥ K` | `Alt` `K` |
## **Quest**
| **Command** | **macOS** | **Windows** |
| :------------------- | :-------- | :---------- |
| Open the Quest panel | `⌘ E` | `Ctrl E` |
# Configure a Network Proxy
If your company network restricts direct internet access, you may need to configure a network proxy for Qoder IDE to function properly.
## **Why a proxy is needed**
Many corporate networks use an HTTP proxy server to inspect outbound traffic before it reaches the Internet. This helps enforce security policies by detecting suspicious activity and blocking unauthorized access. In such environments, Qoder IDE must be configured to route requests through the proxy.
## **How to configure a network proxy**
1. Go to **Preferences** > **Qoder IDE Settings**.
Under **Advanced**, you'll find **Proxy Settings**.
2. Choose one of the following proxy modes:
- Use **system** global configuration (default)\
Qoder IDE automatically uses the proxy settings configured in your operating system.
- Set up a network proxy **manually**\
Enter the proxy address and port. Qoder IDE supports the following proxy types:
- HTTP
- HTTPS
- SOCKS5
> Note: Be sure to provide the complete address, including the protocol and port. Example: `https://127.0.0.xxx:8080`
- No network proxy\
Select this option if no proxy is needed. If you choose manual configuration but leave the field blank, no proxy will be used.
> Important: Ensure the proxy URL is complete and correctly formatted. An incomplete or incorrect configuration may prevent Qoder IDE from accessing online services.
# Remote Control
Qoder Mobile supports remote control for Quest running on your computer. When you need to step away from your desk while Quest tasks are still running, you can use your phone to continue monitoring task progress, approving critical operations, and reviewing plans. This keeps tasks moving by letting you respond at key decision points without having to return to your computer.
[Install Qoder Mobile](https://qoder.com/mobile) on your phone and sign in with your current account. Once signed in, the mobile app automatically links to your IDE account.
Go to **Settings** > **Mobile** and turn on the **Allow Qoder Mobile to control the current device** toggle.
Once enabled, Qoder Mobile can access the local folders of created tasks, allowing you to remotely view and interact with Quest tasks. You can browse task context, check execution progress, and approve operations when a task needs confirmation.
Turn on the **Keep the computer awake** toggle.
This prevents the computer from going to sleep while Qoder IDE is running. If the computer enters sleep mode, the remote connection will be interrupted and running Quest tasks will no longer be accessible remotely. It is recommended to keep this option enabled whenever you use remote control.
After completing these steps, open Qoder Mobile to start controlling Quest tasks running on your computer. Whether you are commuting, between meetings, or briefly away from your desk, you can follow task progress, handle approvals, and provide input at key decision points without returning to your computer.
# Troubleshooting Guide
This guide explains how to use the Qoder IDE diagnostic script to troubleshoot startup and connectivity issues with Qoder IDE. The script automatically collects critical system information, including environment details, network settings, Qoder IDE service status, and relevant logs, enabling quick diagnosis and resolution of common problems.
## **Prerequisites**
Before running the diagnostic script, ensure the following:
- Operating System: Windows
- Permissions: Run the script with administrator privileges for full access to system settings and logs.
- Script file: Download and save the [windows\_Qoder.bat](https://qoder-ide.oss-ap-southeast-1.aliyuncs.com/Diagnosis/windows_qoder.bat) script as a `.bat` file (example: `qoder_Debug.bat`).
- Installation path: Confirm that Qoder IDE is installed in the default directory `C:\Users\\.qoder`.
## **Run the diagnostic script**
### **Step 1: Run the script**
1. Locate the saved `.bat` file.
Example: `qoder_Debug.bat`
2. Double-click the file to execute the script.
3. The script will run automatically, collecting system and application data.
⚠️ Allow the script to complete fully. Do not close the command window prematurely.
### **Step 2: View the generated log**
Once the script finishes:
- A compressed archive (ZIP) containing the collected log files and key configuration files will be automatically generated.\
The filename follows this format: `qoder-diagnosis_YYYYMMDD_HHMMSS.zip`\
*Example: \_*`qoder-diagnosis_Sat_2025-10-11_16-00-03.93.zip`
- The main log file is included in the archive, with the naming format: `Qoder_Log_YYYYMMDD_HHMMSS.txt`\
*Example: \_*`Qoder_Log_20250405_143022.txt`
- You can send the entire diagnostic ZIP package to the Qoder official team to assist with issue investigation and troubleshooting.
##
## **Common issues**
| Issue type | Issue | Solution |
| ----------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Network | Check proxy settings | The script checks whether a proxy is enabled. Review the section `[Network Settings 0x0 means proxy is disabled]` to confirm expected behavior. If a proxy is in use, manually configure the network proxy for Qoder IDE in the settings. |
| Qoder IDE Server Status | Existence of Qoder.exe | The script verifies if Qoder.exe exists. If an error occurs: 1. Check the installation path. 2. Delete the .qoder directory. 3. Restart your IDE to regenerate the directory. |
| | Version and startup test | Check the \[Version Test] and \[Start Qoder IDE] sections to confirm: \* Qoder IDE version \* Connection to the public server If it shows "failed," use the URL from the error message to configure proxy access in settings. |
| | Qoder.exe running but logon fails | Add the executable to Windows Firewall whitelist: Path: 1. windows:C:\Users\用户名\AppData\Local\Programs\Qoder\resources\app\resources\bin\`CPU\_architecture\_64\_system`\Qoder.exe 2. Mac:/Applications/Qoder.app/Contents/Resources/app/resources\bin\`CPU\_architecture\_64\_system\`\Qoder Steps: Control Panel → System and Security → Windows Defender Firewall → Allowed Apps → Allow another app Then retry login. |
| System compatibility | System and hardware information | The script collects: \* OS version (e.g., Windows 10/11) \* CPU model Check \[Operating System Information] to ensure your system meets Qoder IDE's requirements: \* Windows 10 or later (64-bit) \* x86\_64-compatible CPU |
| Log analysis | Qoder IDE application logs | The generated log includes the last 80 lines of `qoder.log`. Use this to identify runtime errors, warnings, or connection issues. |
| | Directory structure and file size | The script lists the full directory structure and file sizes under .qoder. Use this to: \* Check disk usage. \* Verify file integrity (such as missing or abnormally small files). |
| Note | Binary execution restrictions | Some corporate environments restrict or block binary execution, which may prevent Qoder IDE from running. If the app fails to start, contact your IT department for permission adjustments. |
| Unresolvable issues | Issues beyond self-troubleshooting | If you cannot resolve the issue, contact us at: [contact@qoder.com](mailto:contact@qoder.com). Please attach the generated log file: `Qoder_Log_YYYYMMDD_HHMMSS.txt` for faster support. |
# FAQ
These FAQs answer common questions about Qoder IDE, including installation, login, supported platforms, language compatibility, data security, billing, network issues, and troubleshooting.
If you encounter any issues, please try restarting Qoder IDE first. If the problem persists, contact us at [contact@qoder.com](mailto:contact@qoder.com). Our support team will assist you as soon as possible.
## Getting started
### What should I do if Qoder IDE is stuck on "Qoder IDE starting"?
Try the following steps:
1. Check your environment. a. Ensure Qoder IDE is updated to the latest version. b. Confirm your operating system and system architecture support Qoder IDE.
2. Test network connectivity.
a. Run the following command in your terminal to check connectivity. If you receive`pong`, your network is connected. Otherwise, check your firewall or ask your IT admin to whitelist these domains.
```bash
curl https://{hosts}/algo/api/v1/ping
// You can replace {hosts} with any of the following options:
1. api1.qoder.sh
2. api2.qoder.sh
3. api3.qoder.sh
```
b. If you need to use a proxy, set the proxy address in the following format:
```plaintext
http(s)://username:password@proxy_server_address:port
```
c. Clear DNS cache:
- Windows: `ipconfig /flushdns`.
- macOS: `sudo killall -HUP mDNSResponder`.
1. Clear the local cache.
a. Terminate the Qoder IDE process.
b. Delete the `.Qoder` directory:
- Windows:
- `C:\Users\[username]\.Qoder`
- C:\Users\Username\AppData\Local\Programs\Qoder\\
```
Windows:
C:\Users\[username]\.Qoder
C:\Users\Username\AppData\Local\Programs\Qoder\
macOS:
/Applications/Qoder.app
```
c. Restart Qoder IDE.
1. Manually startup if the issue persists:
a. Go to the directory: `.Qoder/bin/x.x.x/CPU_architecture_64_system/`
```
Windows:C:\Users\Username\AppData\Local\Programs\Qoder\resources\app\resources\bin$version`CPU_architecture_64_system`\Qoder.exe
Mac:/Applications/Qoder.app/Contents/Resources/app/resources\bin$versionCPU_ahicture_64_system\Qoder
```
b. Run:
```bash
Qoder.exe start or Qoder start
```
c. Try logging in again.
2. (Optional) Troubleshooting security issues
a. If you see an "incompatible program" message or Qoder IDE won't start:
i. Click the Qoder IDE icon in the bottom right corner, and select **Advanced Settings**.
ii. Move the extraction path to a non-C drive folder ( because your company might restrict users' read or write access to the C drive), and make sure the path ends with an empty folder.
iii. Restart Qoder IDE.
b. Add Qoder IDE to firewall/Security Software allowlists:
i. **Control Panel** > **System and Security** > **Windows Defender Firewall** > **Allowed apps**.
ii. Company security software may also require you to allow:
```plaintext
Windows:
C:\Users\Username\AppData\Local\Programs\Qoder\resources\app\resources\bin\$version\CPU_architecture_64_system\Qoder.exe
C:\Users\Username\.qoder\bin\qoder.exe
Mac:
/Applications/Qoder.app/Contents/Resources/app/resources\bin\$version\CPU_architecture_64_system\Qoder
```
````
## Login and Permissions
### What if login fails or I see a permission denied error?
- Expired login sessions will require you to try again.
- Ensure your network allows access to the domains listed below and proxy (if required) is configured. See [Configure a network proxy](https://docs.qoder.com/user-guide/configure-network-proxy) for details.
```plaintext
api1.qoder.sh
api2.qoder.sh
api3.qoder.sh
````
- After changing settings, completely exit Qoder IDE and relaunch.
### Proxy and Connectivity
- Qoder IDE supports HTTP, HTTPS, and Socks5 proxies. Configure these inside Qoder IDE’s settings. For more details, see [Configure a network proxy](https://docs.qoder.com/user-guide/configure-network-proxy).
- To test connection, run:
```powershell
curl https://{hosts}/algo/api/v1/ping
//You can replace {hosts} with any of the following options:
1. api1.qoder.sh
2. api2.qoder.sh
3. api3.qoder.sh
```
If `pong` is returned, your network is connected to the Qoder server.
### **How to troubleshoot network issues?**
To better assist you with resolving the issue, please follow the steps below and provide the relevant information:
1. Go to "Qoder IDE Settings" > "Network" > Run Diagnostics, and send us the complete diagnostic results.
2. Are you currently using a VPN, proxy, or corporate network? If so, please try disabling these services or switching to another network connection.
3. Try selecting different model tiers in the chat interface to see if there is any improvement in response speed.
4. If the issue persists after the above steps, please provide the following information for further investigation:
- Specific examples of delays along with corresponding timestamps;
- Open "Help" > "Toggle Developer Tools" > Check the console error logs and send screenshots;
- Does this issue occur across all projects or only within a specific workspace?
- Can other users reproduce this issue under the same network conditions?
Please submit the above information via the "Issue Reporting" feature.
## **Account Management**
### How do I change or reset my account password?
You can reset your password yourself from the login page. On the [Qoder login page](https://qoder.com/), enter your account email and click **Continue**; on the password step, click the **Forgot password?** link next to the password field, then follow the on-screen guide to set a new password. You can then sign in with the new password.
### **My account is suspended. How can I reactivate it?**
If your account was suspended due to **having too many free trial accounts**, you can reactivate it by following these steps:
1. Sign in to the [Qoder website](https://qoder.com/), click your avatar in the \
top-right corner, and go to **Settings** > **Usage**.
2. On the Usage page, find the suspension notice banner at the top and click Reactivate Account.
3. **Confirm the policy notice:** Our policy allows the free Pro Trial only on your **first account** to prevent abuse. Reactivating \
will forfeit any remaining Credits (resetting them to zero) of this account. Once confirmed, this account will automatically reactivate and return to normal use.
### Why was my Pro Trial revoked?
According to our Terms of Service:
- The Pro trial (including the 300 Credits trial allowance) is limited to one time per user. Any trial obtained by registering multiple accounts will be revoked.
- Using the Pro trial on virtual machines is not supported.
Therefore, your Pro trial has been revoked and you have been notified via email. You can still continue to use Qoder. If you need more Credits, please [visit our website](https://qoder.com/pricing) to upgrade your subscription plan.
### How much does it cost?
Qoder offers flexible pricing to suit a variety of needs. New users are eligible for a free 2-week Pro Trial, giving them full access to all Pro-exclusive features.
After your trial ends, you have several options:
- Upgrade to the Pro plan
- Upgrade to the Pro+ plan, and get 3 times the Credits allowance compared to the Pro plan
- Upgrade to the Ultra plan, and get 10 times the Credits allowance compared to the Pro plan, suitable for heavy Agent users
- Upgrade to the Team or Enterprise edition
- Do nothing and be automatically downgraded to our Free
Usage on Qoder is measured in Credits. Each paid plan includes a specific amount of Credits, allowing you to choose the plan that best fits your needs. For more details, please visit our [Pricing](https://qoder.com/pricing) Page.
Please note that all prices shown exclude applicable taxes (such as VAT or sales tax) unless stated otherwise. The final tax amount depends on several factors, including but not limited to your billing address or tax registration number.
To ensure a fair trial experience for all users, the Pro Trial is limited to one account per user. Any additional trial accounts created will be suspended.
### How does the Pro trial work?
When new users sign in to any Qoder Client, including the Qoder IDE, Qoder CLI, or JetBrains Plugin (**requires latest version; not available on virtual machines**) for the first time, they will receive a one-time, free 2-week (14-day) Pro trial. This trial includes 300 Credits and full access to Pro-exclusive features. Upon expiration, your account will be automatically downgraded to the Free, and any unused trial Credits will be cleared.
If you upgrade to a paid plan (Excluding the Teams edition) before the trial ends, your remaining trial Credits will be automatically converted into a Credit Pack and will remain in your account with their original expiration date. This ensures you won't lose any unused Credits for upgrading early.
To ensure a fair trial experience for all users, the Pro Trial is limited to one account per user. Any additional trial accounts created will be suspended.
### What happens when my free trial ends?
You have several options when your trial ends. You can choose to:
- Upgrade to a paid plan: Choose a subscription that best fits your needs to unlock more resources. See our [Pricing](https://qoder.com/pricing) Page.
- Switch to the Free: You can always use our Free, which is perfect for BYOK scenarios.
### What happens if I run out of my Credits during the trial?
You can upgrade to the Pro, Pro+, or Ultra plan at any time to get more Credits. If you choose to stay on the Free, you can use BYOK to connect models.
When using the basic model, here's what changes:
- You'll switch to the Basic Model: You can continue to use our service with a daily usage limit.
- Performance may vary: The Basic Model is not as powerful for complex tasks.
### **What should I do if I reach my usage limit?**
For the usage of lightweight free models, there are daily and monthly usage limits that refresh at the corresponding periods.
If you trigger the usage limit prompt for lightweight free models when using Q\&A or inline editing, please switch to other model types such as Auto to continue using. If you have no Credits available, please [upgrade your subscription plan](https://docs.qoder.com/account/pricing) before continuing.
## Teams
### What is the Teams subscription plan?
For organizational and team use cases, we have launched the Teams subscription plan, which includes but is not limited to the following features, and continues to evolve:
- Centralized payment for organizational bills
- Centralized admin console, supporting enforced management of member access permissions, data privacy mode, etc.
- Support for account domain restrictions and access control for non-domain accounts
- Support for Single Sign-On (SSO)
For details, see [Teams Information](https://docs.qoder.com/account/teams/teams-pricing).
### **Can the Credits allowance included with a seat be shared within the organization?**
The Credits for a seat cannot be shared within the organization.
- Each seat includes a 2000 Credits allowance. The seat's allowance cannot be transferred or shared.
- A seat's Credits are only valid for the current subscription period. At the end of the subscription period, any unused Credits will automatically be reset to 0.
To solve the issue of some members having insufficient credits within a subscription period, we will soon be launching a shared resource pack to replenish Credits on demand.
### **Why is my Credits quota lower than others?**
A seat's Credits quota is determined by when it was purchased or activated. If a seat is added mid-cycle, both the fee and the allocated quota will be **prorated** for the remaining time. Don't worry, your quota will be restored to the full amount at the start of the next cycle.
- **For organizations that purchased seats directly from our website:** The available quota for the current cycle depends on the seat's purchase date. If a seat is purchased mid-billing cycle, the initial fee and the available quota are **prorated** based on the remaining time. Your quota will reset to the standard amount at the beginning of the next full billing cycle.
- **For organizations that redeemed via a cloud marketplace:** The available quota for the current cycle is determined by the date you joined the organization. If you join mid-billing cycle, both the initial cost and the available quota are **prorated** based on the remaining time. Your quota will reset to the standard amount at the beginning of the next full billing cycle.
### **Can the Teams issue Chinese-style invoices?**
Purchases made on the official website support downloading purchase service invoices, but do not support issuing official Chinese-style invoices.
You can purchase redemption codes through third-party channels that support issuing Chinese invoices. Currently, Qoder is available for purchase on the [****Alibaba Cloud Chinese Marketplace****](https://market.aliyun.com/detail/cmgj00072560.html?spm=5176.730005.result.2.bbb8414aScXLKN\&innerSource=search_qoder#sku=yuncode6656000001). The value, usage rules, and validity period of a redemption code are subject to the rules of the channel from which it was purchased.
If purchasing through a third-party channel, please consult with the channel beforehand to confirm if they can issue an invoice in the required format.
For purchasing redemption codes through third-party channels, please refer to the [**instructions**](https://docs.qoder.com/account/teams/about-redeem).
### **How are seats billed?**
Seats are charged based on the number of members with billable roles in the organization. When a member with a billable role is added, one seat is immediately and automatically consumed. If there are not enough available seats, you will not be able to add new members with billable roles. In this case, please manually upgrade your seat count to ensure members can be added and use the service normally.
A seat becomes active immediately on the day of purchase, and the subscription period begins. It expires at the end of the subscription period.
See more [**billing information**](https://docs.qoder.com/account/teams/teams-pricing#how-seats-are-billed).
If an organization is created via redemption code mode, adding a member with a billable role will automatically consume one seat-month from the balance. The seat-month credits redeemed into the organization's balance are valid for 2 years and can be used anytime within the validity period. The organization balance from redeemed codes does not expire with the subscription period. For purchasing redemption codes, please see the [**instructions**](https://docs.qoder.com/account/teams/about-redeem).
### Why can the charge for adding or upgrading seats be higher than the monthly unit price shown on the page?
The monthly price or seat-month price displayed on the pricing page is the standard monthly unit price. For a new subscription, the expiration time is aligned to 00:00 on the expiration date, and the remaining time on the purchase date is provided at no charge. When seats are added to or upgraded on an active subscription, no additional service time is granted. The billable period for an upgrade starts when the upgrade order is submitted or takes effect and is calculated to the second until the instance's original expiration time. The prorated number of months is calculated as follows:
**Prorated months = remaining service seconds ÷ (3600 × 24 × 30)**
For example, if a subscription is purchased at 10:30 on July 8, the instance actually expires at 00:00 on August 8. If the subscription is upgraded on the purchase date, the period from the upgrade start time to 00:00 on August 8 may exceed 30 days. The prorated number of months may therefore be greater than 1, and the upgrade charge may be higher than one standard monthly unit price. An upgrade does not extend or shorten the instance's original expiration time.
The actual billing start and end times, discounts, taxes, amount, and rounding result are subject to the order checkout page.
### **Why did I get a "Join Organization Failed" error when trying to log in?**
If you encounter the "Join Organization Failed" error during login, it means your email domain has been linked to a Qoder Teams organization by your administrator. This setting is designed to automatically add all accounts under that domain to the organization. However, the process failed because the organization has run out of available seats.
To resolve this, please contact your company's IT administrator and ask them to purchase more seats. Once additional seats are available, simply try logging in again. You will then be automatically added to the organization and can start using the Teams Plan.
## Supported platforms
- macOS: 11.0 and above
- Windows: 10/11
## Supported Programming Languages
Qoder IDE supports all major languages with enhanced experience in:
- JavaScript, TypeScript, Python, Go, C/C++, C# and Java
## Data security
### Does Qoder IDE store my code?
- Qoder IDE does not store or share your code. During code completion, your code context is required but is never stored or used for other purposes.
- Chat logs (except actual code) may be anonymized for algorithm improvement only if you explicitly submit feedback (e.g., thumbs up/down).
See [Privacy policy](https://qoder.com/privacy-policy) for details.
### Is my code snippet shared with other users?
No. The system does not share your code snippets with other users. When using the large language model for code completion, we need to get your code context information to complete the completion, but the context information will not be stored or used for any other purpose.
### Can I directly use the code generated by Qoder IDE?
The code generated by Qoder IDE is only suggested code. Its usability cannot be guaranteed, and developers should review the code themselves and decide whether to adopt it.
## Troubleshooting & Common Issues
### High CPU or Memory Usage
- Large projects may cause high resource consumption during code indexing.
- Add file patterns or directories that don't need to be indexed to `.qoderignore` at your project root ( just like `.gitignore`).
- After editing `.qoderignore`, restart Qoder IDE.
### Qoder IDE Extension Host Crash
**Error**: "extension host terminated unexpectedly 3 times within the last 5 minutes"
- May be caused by a memory leak.
- Use the [extension bisect](https://code.visualstudio.com/blogs/2021/02/16/extension-bisect) to confirm if Qoder IDE is causing the issue.
- Try reinstalling Qoder IDE and restarting.
- On Windows, ensure security software isn't blocking Qoder IDE.
If the issue continues, email us with [contact@qoder.com](mailto:contact@qoder.com) .
- OS and Qoder IDE version
- Steps to reproduce
- Verbose Qoder IDE logs (run `qoder --verbose`)
- For crash dumps: run `qoder --crash-reporter-directory `, reproduce the error, and send us any `.dmp` files.
## Support
If you need further assistance, please contact us at [contact@qoder.com](mailto:contact@qoder.com).
# MCP Common Issues
This guide helps you diagnose and resolve common issues when installing and running Model Context Protocol (MCP) servers, including missing environments, server initialization failures, and configuration errors.
## **Failed to add or install the MCP servers**
### **Issue: NPX environment missing**
#### **Error message**
`failed to start command: exec: "npx": executable file not found in $PATH`
#### **Cause**
The `npx` command-line tool, part of the Node.js ecosystem, is not installed or not accessible in your system’s `PATH`.
#### **Solution**
Install [Node.js](https://nodejs.org/) V18 or later (which includes NPM V8+ ). Earlier versions may cause tool failures.
#### **Installation steps**
- Windows
Install [nvm-windows](https://github.com/coreybutler/nvm-windows) to manage multiple versions:
```shellscript
nvm install 22.14.0 # Install a specified version.
nvm use 22.14.0
```
Verify the installation.
```shellscript
node -v
npx -v
```
Then, the terminal will display the installed Node.js version number.
- **macOS**
Use Homebrew (install first if needed).
```shellscript
# 1. Update Homebrew and install Node.js.
brew update
brew install node
# 2. Verify installation and confirm the versions.
echo "Node.js version: $(node -v)"
echo "npm version: $(npm -v)"
echo "npx version: $(npx -v)"
# 3. Configure environment variables (if necessary).
echo 'export PATH="/usr/local/opt/node@16/bin:$PATH"' >> ~/.zshrc
```
### **Issue: UVX environment missing**
#### **Error message**
`failed to start command: exec: "uvx": executable file not found in $PATH`
#### **Cause**
The `uvx` command, used to run Python scripts in isolated environments via `uv`, is not installed.
#### **Solution**
Install `uv`, a fast Python package installer and virtual environment manager.
**Installation steps**
- Windows
```shellscript
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```
- macOS and Linux
```shellscript
curl -LsSf https://astral.sh/uv/install.sh | sh
```
Verify the installation.
```shellscript
uv --version
```
Then, the terminal will display the installed uv version number.
### **Issue: Unable to initialize MCP Client**
#### **Error message**
`failed to initialize MCP client: context deadline exceeded`
#### **Possible causes**
- Incorrect MCP servers parameters
- Network issues preventing resource download
- Corporate network security policies blocking initialization
#### **Solution**
1. Click **Copy complete command** in the UI.
2. Run the command in the terminal to get detailed error output.

3. Analyze and resolve based on the specific error.
**Common issue 1**: Configuration error
The error may indicate an invalid configuration, such as an incorrect Redis connection URL.
Fix: Review and correct the configuration in the MCP servers settings.
**Common issue 2**: Node.js blocked by security software
Corporate security tools may block Node.js execution.
Fix: Add Node.js or the relevant process to the whitelist in your security software.
## **Tool usage issues**
### **Issue: Tools fail due to environment or parameter errors**
#### **Symptoms**
Unexpected behavior or errors when calling MCP tools.
#### **Cause**
Some MCP servers (e.g., MasterGo, Figma) require manual configuration of `API_KEY` or `TOKEN` in the arguments during setup.
#### **Solution**
1. In the upper-left corner of your Qoder IDE, click the user icon or use the keyboard shortcut (`⌘` `⇧` `,` (macOS)or`Ctrl` `shift` `,`(Windows)), and select **Qoder IDE Settings**.
2. In the left-side navigation pane, click **MCP**.
3. Find the relevant server and click **Edit**.
4. In the **Edit MCP Server** page, check the parameters in **Arguments**.
5. Replace with correct values, reconnect the server, and retry.
### **Issue: LLM fails to call MCP tools**
**Cause 1:** Not in Agent Mode
If no project directory is open, Qoder IDE defaults to Ask Mode, which does not support MCP tool calls.
**Fix:** Open a project directory and switch to Agent Mode.
**Cause 2:** MCP server not connected
A disconnected server prevents tool invocation.
**Fix**: Click Retry icon in the interface. The system will attempt to restart the MCP server automatically.
> **Best Practice:** Avoid naming MCP servers and their tools too similarly (for example, both `TextAnalyzer-Pro` and `TextAnalyzer-Plus` having a `fetchText` tool), to prevent ambiguity during calls.
### **Issue: MCP server list fails to load**
#### Symptoms
The server list shows a continuous loading state.
#### **Solution**
Restart the Qoder IDE IDE and try again.
# Terminal Execution Exceptions
## Introduction
When using Qoder IDE Agent Mode, terminal execution relies heavily on your local environment and shell configuration. You may encounter issues such as:
- Inability to launch the terminal
- Commands not executing
- No output returned
This topic provides common troubleshooting methods to resolve these issues.
### Common troubleshooting methods
#### Method 1: Configure a supported shell
Qoder IDE supports several shells. Ensure you're using a compatible one.
1. Open Qoder IDE.
2. Press`Cmd + Shift + P` (MacOS)or`Ctrl + Shift + P`(Windows/Linux) to open the Command Palette.
3. Type `Terminal: Select Default Profile` and select it.
4. Choose a supported shell:
- Linux/macOS: `bash`, `fish`, `pwsh`, `zsh`
- Windows: `Git Bash`, `pwsh`
5. Completely close and reopen Qoder IDE for changes to take effect.
#### Method 2: Manually install shell integration
If terminal integration still fails, install shell integration manually by adding the appropriate line to your shell’s configuration file.
- zsh (`~/.zshrc`):
```shellscript
[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(code --locate-shell-integration-path zsh)"
```
- Bash (`~/.bashrc`):
```shellscript
[[ "$TERM_PROGRAM" == "vscode" ]] && . "$(code --locate-shell-integration-path bash)"
```
- PowerShell (`$Profile`):
```shellscript
if ($env:TERM_PROGRAM -eq "vscode") { . "$(code --locate-shell-integration-path pwsh)" }
```
- Fish (`~/.config/fish/config.fish`):
```shellscript
string match -q "$TERM_PROGRAM" "vscode"; and . (code --locate-shell-integration-path fish)
```
After editing the file:
1. Save the changes.
2. Restart Qoder IDE completely.
For other shells, refer to manual shell integration.
### If issues persist
If you still don’t receive terminal output:
- Click the "Terminate Terminal" button to close the current terminal session.
- Run the command again. This refreshes the terminal connection and often resolves transient issues.
### Windows-specific troubleshooting
#### Git Bash
1. Download and install Git for Windows from: [https://git-scm.com/downloads/win](https://git-scm.com/downloads/win).
2. Exit and reopen Qoder IDE.
3. Set “Git Bash” as the default terminal:
a. Open the Command Palette.
b. Run: `Terminal: Select Default Profile` .
c. Select Git Bash.
#### PowerShell
1. Ensure you’re using PowerShell 7 or later.\
Check your version:
```powershell
$PSVersionTable.PSVersion
```
2. If needed, update PowerShell .
3. By default, PowerShell restricts script execution for security. You may need to adjust the execution policy.
a. Open PowerShell as Administrator:
- Press `Win + X`
- Select Windows PowerShell (Admin) or Windows Terminal (Admin)
b. Check the current policy:
```powershell
Get-ExecutionPolicy
# If the output is RemoteSigned, Unrestricted, or Bypass, you probably do not need to change the execution policy. These settings should allow shell integration to work properly.
# If the output is Restricted or AllSigned, you may need to change the policy to enable shell integration.
```
c. Update the policy for your user:
```powershell
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
# This will set the RemoteSigned policy for the current user only, which is safer than changing it system-wide.
```
d. Confirm with `Y` when prompted, then verify:
```powershell
Get-ExecutionPolicy
```
e. Restart Qoder IDE and retry.
#### WSL
If using Windows Subsystem for Linux (WSL):
1. Add the following line to your \~/.bashrc:
```sh
. "$(code --locate-shell-integration-path bash)"
```
2. Reload your shell or runsource \~/.bashrc.
3. Retry the terminal command in Qoder IDE.
### Abnormal Terminal Output
**Symptoms:**
- Garbled characters, block symbols
- Escape sequences (e.g., `^[[1m`, `^[[32m`)
- Command output is truncated or formatting is messy.
**Possible Causes:**
Third-party shell personalization configurations, such as Powerlevel10k, Oh My Zsh, or custom Fish themes.
#### Solution 1: Disable Complex Prompts/Themes for Agent Execution (Recommended)
Detect if the Agent is running by checking the `QODER_AGENT` environment variable. If it is active, bypass loading complex themes or prompt configurations during shell startup to avoid conflicts.
**zsh** (`~/.zshrc`):
```bash
if [[ -n "$QODER_AGENT" ]]; then
# Skip theme during Agent execution
else
[[ -r ~/.p10k.zsh ]] && source ~/.p10k.zsh
fi
```
**Bash** (`~/.bashrc`):
```bash
if [[ -n "$QODER_AGENT" ]]; then
PS1='\u@\h \W \$ ' # Use simple prompt during Agent execution
fi
```
#### Solution 2: Temporarily Disable
Comment out theme-related configurations in your shell config file and restart Qoder IDE to test. If the issue is resolved, re-enable items one by one to locate the conflicting component.
For example, commenting out Powerlevel10k in `~/.zshrc`:
```bash
# source /path/to/powerlevel10k/powerlevel10k.zsh-theme
```
# Introduction
Qoder is an agentic coding platform designed for real software development. And here **Qoder Plugin** brings the agentic coding to **JetBrains IDEs**, empowering developers to command AI agents without ever leaving the comfort of their IDE.
It goes beyond simple code completion. Qoder helps you think deeper, code smarter, and build better by automating intricate workflows, maintaining project context, and enabling seamless AI-assisted development.
## **Code suggestion: Codebase-aware code completion**
Qoder’s code completion engine goes beyond single-file analysis to understand the context of your entire project. By analyzing your codebase, dependencies, and existing patterns, it provides intelligent suggestions that are both syntactically correct and architecturally consistent.
**Key Capabilities:**
- **Whole-function generation:** Generates complete functions and code blocks, not just single lines.
- **Predictive suggestions:** Anticipates your next coding step based on the broader context of your work.
- **Architectural consistency:** Suggestions align with your project’s existing design patterns and coding style, reducing the need for refactoring.
This feature is designed to keep you in a state of flow, minimizing repetitive coding and allowing you to focus on higher-level problem-solving.
## **Ask Mode: Conversational problem solving**
Ask Mode acts as an integrated AI expert that you can consult directly within your IDE. It synthesizes information from a vast knowledge base of technical documentation with a live understanding of your project's code to provide accurate, context-aware answers.
**Use it to:**
- **Debug code:** Paste code snippets and error messages to get step-by-step debugging guidance.
- **Troubleshoot runtime errors:** Understand the root cause of cryptic errors and receive actionable solutions.
- **Explain concepts:** Ask for explanations of unfamiliar APIs, libraries, or programming concepts.
- **Explore solutions:** Discuss implementation strategies and architectural choices before writing code.
Ask Mode eliminates the need to switch to a browser, keeping your development process smooth and uninterrupted.
## **Agent Mode: Autonomous task completion**
Agent Mode allows you to delegate complex, multi-step development tasks to Qoder. Simply describe your objective in natural language, and the agent will autonomously create a plan and execute it from start to finish.
**How it works:**
1. **Objective:** You provide a high-level goal (e.g., "Refactor the `UserService` to use async/await").
2. **Planning:** The agent breaks the objective down into a series of logical steps.
3. **Execution:** It utilizes a suite of integrated tools to carry out the plan.
**Integrated Tools:**
- Codebase Search and Navigation
- File Reading and Editing
- Integrated Terminal for running commands (e.g., `npm install`, `git commit`)
Use Agent Mode for end-to-end tasks like implementing new features, writing unit tests, or performing large-scale refactorings.
## **Customization: MCP & project rules**
Qoder can be precisely tailored to your specific project needs and team standards through two primary mechanisms.
- **Project-specific rules:** By creating configuration files in the `.qoder/rules` directory, you can instruct Qoder on your project's specific conventions. This ensures that its suggestions and actions align with your preferred frameworks, coding styles, and architectural patterns.
- **Model Context Protocol (MCP):** MCP is an integration layer that allows Qoder to connect to external data sources. You can use it to provide additional context, such as your company's internal documentation, private APIs, or database schemas, enabling Qoder to generate code that is fully compliant with your proprietary systems.
## Supported JetBains IDEs and versions
Requires JetBrains IDEs version **2020.3 or later**. The plugin is fully compatible with both local and remote development environments.
**Supported IDEs include:**
- IntelliJ IDEA
- Android Studio
- PyCharm
- GoLand
- CLion
- ...and other JetBrains IDEs.
**Remote development:**
- The plugin is fully functional within JetBrains Remote Development workflows (including SSH, WSL, and Dev Containers).
## Sign up for Qoder
Every developer is invited to [Sign up](https://qoder.com/users/sign-up) for a free Qoder account and will receive 300 Credits upon successful registration. Should you need more, you can easily purchase a plan at any time. You can read more about our offerings for individuals and businesses at [https://qoder.com/pricing](https://qoder.com/pricing).
# Quick Start
Qoder plugins bring the agentic coding to JetBrains IDEs, empowering developers to command AI agents without ever leaving the comfort of their IDE.
1. Ensure your operating system is macOS, Windows, or Linux.
2. Download and install a compatible version of JetBrains IDEs (2020.3 or later), Qoder supports all JetBrians IDEs like IntelliJ IDEA, Android Studio, PyCharm, GoLand, CLion and more.
**Method 1: Install from marketplace**
1. Open your JetBrains IDE and navigate to the **Settings** page (Press `⌘ ,` on macOS and `Ctrl Alt S` on Linux/Windows).
2. Search Qoder Plugin quickly by typing `Qoder` in the input box and clicking `Enter`.
3. Click **Install**.
**Method 2: Manual installation**
If you encounter any issues while installing the Qoder Plugin from the JetBrains Marketplace, you can install as follow steps:
1. Click the following link and download the installation package.
[Qoder\_JetBrains\_latest](https://download.qoder.com/qoderjb/qoder-jetbrains-latest.zip)
2. Open your JetBrains IDE and navigate to the **Settings** page.
3. Select **Plugins**.
4. Click the settings icon and then **Install Plugin from Disk**.
5. Open the downloaded `.zip` file to install it.
After the installation is complete, restart the JetBrains IDE.
1. Click the Qoder icon in the right-side navigation bar.
2. Click **Sign in** in the displayed section.
Choose to work with an local project or clone a sample from GitHub.
- **Trigger code suggestions in the Editor**
1. Enter a partial code snippet or a code request in natural language. Example: "Initialize a list."
2. Press `⌥ P` (macOS) or `Alt P` (Windows/Linux). Suggestions will appear automatically.
3. Press **Tab** to accept a suggestion.
Code suggetions of Qoder Plugin supports multi-line edits, and seamless autocomplete.
- **Initiate an inline chat**
Use Inline Chat to get AI help directly within your code context.
1. In the editor, press `⌘ ⇧ I` (macOS) or `Ctrl Shift I` (Windows/Linux). The Inline Chat window will open.
2. Type your request and press **Enter**. Example: "Add a method for handling file updates."
3. To apply the AI-generated code, press `⌘ ⏎` (macOS) or `Ctrl Enter` (Windows/Linux).
- **Start a chat**
Click the Qoder icon in the navigation bar or press`⌘ ⇧ L` (macOS) or `Ctrl Shift L` (Windows/Linux) for broader tasks in Ask or Agent Mode.
1. In the Chat panel on the right, enter your request. Example: "Create tests for this function and run them.”
2. Press **Enter**. The AI agent will generate a test file with relevant test cases.
3. Click **Run** as prompted to execute the tests.
# Agentic Chat
Agentic Chat moves beyond simple Q\&A, empowering an AI agent to autonomously use tools, make decisions, and execute complex tasks directly from the chat panel. It’s the ultimate shift from a passive assistant to an active development partner.
Agentic Chat has the following core capabilities:
- **Codebase awareness:** Qoder automatically understands the full context of your task by intelligently analyzing your project and natural language descriptions.
- **Project-level changes:** Based on your high-level instructions, Qoder can perform complex, multi-file changes across your entire project.
- **Memory awareness:** Qoder features a persistent, LLM-based memory, allowing it to learn and adapt to you and your projects over time.
- **Tool use:** To accomplish complex tasks, Qoder can autonomously select and use a powerful suite of built-in tools.
- **To-dos:** For complex objectives, Agent Mode generates a structured, step-by-step task list to guide its work.
- **Command execution:** Qoder intelligently determines, generates, and executes necessary terminal commands to complete its tasks.
## How to use Agentic chat
To start a chat after installing Qoder Plugin on JetBrains IDEs, click the Qoder icon in the side navigation bar or use the keyboard shortcuts (Press`⌘ ⇧ L` on macOS or `Ctrl Shift L` on Windows/Linux) to open the Chat panel. Sign in, and you can start chatting.
Qoder Plugin provides Chat capabilities in two modes:
- **Ask Mode** help developers solve coding problems, fix errors, debug, and troubleshoot runtime errors
- **Agent Mode** offers to-dos generation, multi-file edits, autonomous decision-making, codebase-level awareness, and tool use to complete end-to-end coding tasks.
## Features
### Codebase indexing
Qoder automatically indexes your project, giving the AI a deep understanding of your code for smarter search and more relevant suggestions—all in real time. [Learn more ➔](https://docs.qoder.com/user-guide/indexing)
### Memory
Qoder remembers your conversations, building a personal memory of you and your projects for smarter assistance and more relevant solutions—getting more helpful with every chat. [Learn more ➔](https://docs.qoder.com/user-guide/chat/memory)
### Rules
Qoder enforces your custom project rules, guiding the AI to understand your unique coding standards for suggestions that consistently match your project's style—ensuring it always codes your way. [Learn more ➔](https://docs.qoder.com/user-guide/rules)
### Tools
Qoder equips its AI with powerful tools, letting it read files, run commands, and edit your code to solve problems autonomously—turning conversation into concrete action. [Learn more ➔](https://docs.qoder.com/user-guide/chat/tools)
### To-dos
Qoder breaks down your complex goals into a step-by-step plan, providing a transparent roadmap of its actions for easy tracking and approval—turning a big idea into a clear path forward.
### Web search
Qoder gives its AI live web access, enabling it to solve complex problems and answer questions using the most current online resources—breaking free from the limits of static training data.
### Terminal
Qoder gives its AI direct control of the terminal, letting it install packages, run tests, and manage servers to complete tasks from start to finish—automating the manual work so you don't have to.
### MCP
Qoder Agent Mode connects to your external tools via MCP, letting the AI interact with services like JIRA and custom APIs for richer context and automated actions—extending its power far beyond just code. [Learn more ➔](https://docs.qoder.com/user-guide/chat/model-context-protocol)
### Checkpoints
Qoder Agent Mode provides a safety net by automatically saving snapshots of the project's state, allowing you to easily revert any changes made by the agent.
### History
Qoder offers a complete audit trail of every action the agent has taken, including commands run and files modified, for full transparency. You can access History via opening the Qoder **Chat** panel and clicking the icon.
## **Keyboard shortcuts**
| **Action** | **macOS** | **Windows/Linux** |
| :--------------------------- | :-------- | :---------------- |
| Submit a message | `⏎` | `⏎` |
| Insert a new line in input | `⇧ ⏎` | `Shift ⏎` |
| Add context | `@` | `@` |
| Add selected to chat | `⌘ ⌥ I` | `Ctrl Alt I` |
| Accept all suggested changes | `⌘ ⏎` | `Ctrl ⏎` |
| Reject all suggested changes | `⌘ ⌫` | `Ctrl Backspace` |
# NEXT Code Suggestions
Predict your coding intent and generate the next code segment.
NEXT is Qoder's core intelligent coding feature. It dynamically predicts code changes based on the complete context of your current code, combined with code modifications and cursor position. With Qoder NEXT, you can efficiently complete code changes with just a Tab.
## Core Capabilities of NEXT
- **Intelligent Context Awareness** - Analyzes not only the current file but also the broader project context, including:
- Immediate context of the current file
- Recently opened files and other recent files
- Dependencies and relationships between different files across the codebase
This ensures code suggestions are not only functionally accurate but also fully aligned with your project's established coding standards and architectural patterns.
- **Line-level and Method-level Completion** - Provides multi-level code suggestions from single lines to complete methods
- **Proactive Need Prediction** - AI predicts your needs without asking, proactively providing intelligent suggestions at the cursor position
- **Multi-line Smart Editing** - Edit multiple lines of code at once near the cursor
- **Continuous Learning** - Optimizes suggestions based on recent changes and previously accepted edits
- **Automated Assistance** - Automatically imports dependencies, reducing manual operations
## How to Use NEXT
### Enable Settings
Before using NEXT, confirm that the feature is enabled in Qoder plugin settings.
### Triggering Methods
**Automatic Trigger:**
- Automatically generates code suggestions as you write code
- Also triggers intelligent suggestions when you enter natural language prompts in comments
**Manual Trigger:**
- Press `⌥ P` (macOS) or `Alt P` (Windows/Linux) to request code suggestions
### Suggestion Display Modes
Qoder intelligently adjusts the display mode of suggestions to provide the best comparison experience:
**Ghost View:** By default, code completions are displayed as gray text.
**Side-by-Side View:** If there are multiple modifications inline/between lines, it automatically displays in a side-by-side Diff view for easy comparison.
**Inline View:** If code changes are too wide to display comfortably in the editor, Qoder automatically switches to inline view to ensure readability and avoid horizontal scrolling.
### Accept or Reject Suggestions
When code suggestions appear in the editor, you can:
**Using Mouse:**
- Hover over "Accept/Reject" to operate
**Using Keyboard:**
| **Action** | **macOS** | **Windows/Linux** |
| :------------------------------ | :-------- | :---------------- |
| **Accept suggestion** | `Tab` | `Tab` |
| **Reject suggestion** | `Esc` | `Esc` |
| **Manually trigger suggestion** | `⌥ P` | `Alt P` |
### Cross-location Navigation
**Same-file Navigation:** If the next edit location is not in the current view, click "Tab to Jump" or press `Tab` to jump to the edit location in the same file.
**Cross-file Navigation:** If the edit is in another file, click "Tab to Jump" or press `Tab` to jump to the edit location in the target file.
## Typical Use Cases
### Consistent Renaming
When you rename a variable or function, NEXT prompts you to update all occurrences of that identifier throughout the file, ensuring consistency with a single click.
### Smart Refactoring
Discovers opportunities to simplify code, such as converting code blocks to more modern syntax or extracting logic into separate methods, and presents the refactored code for your review and approval.
### Function Parameter Updates
After adding new parameters to a function definition, automatically suggests updating all call sites that use the function, eliminating tedious manual searching.
### Pattern Completion
After you declare a new variable or add annotations to a class field, predicts the next logical operation—such as initializing that variable or applying similar annotations to other fields—and provides corresponding code suggestions.
### Instant Documentation
Place the cursor above a function and type `/` to trigger automatic suggestions that generate complete, context-aware comment blocks (such as JSDoc), describing the function, its parameters, and return values.
# Inline Chat
Inline Chat brings the power of AI directly into your editor, allowing you to refactor, generate, and understand code without ever leaving your file. It's the fastest way to make targeted changes and get contextual answers.
## **How to use Inline Chat**
To start an Inline Chat, select a code block to modify it or place your cursor to generate new code, then use the keyboard shortcut (Press`⌘ ⇧ I` on macOS or `Ctrl Shift I` on Windows/Linux) to open the chat window.
## **Scenarios**
**Scenario 1: Refactoring or modifying existing code**
This is perfect for improving, commenting, or changing a block of code.
1. **Select** **the code** you want to modify.
2. Press `⌘ ⇧ I` (or `Ctrl Shift I`) to open Inline Chat.
3. Type your request, for example:
- *"Refactor this to be more efficient."*
- *"Add JSDoc comments to this function."*
- *"Convert this to an async/await function."*
4. Qoder will analyze your request and generate the changes directly in a diff view for your approval.
**Scenario 2: Generating new code snippets**
Use this to write new functions, boilerplate, or test cases from scratch.
1. **Place your cursor** on an empty line where the new code should go.
2. Press `⌘ ⇧ I` (or `Ctrl Shift I`) to open Inline Chat.
3. Type your request, for example:
- *"Write a function that fetches data from 'api/users'."*
- *"Generate a regular expression to validate an email address."*
4. Qoder will generate the new code snippet in place.
## **Keyboard shortcuts**
| **Action** | **macOS** | **Windows/Linux** |
| :--------------------------- | :-------- | :---------------- |
| Open an inline chat | `⌘ ⇧ I` | `Ctrl Shift I` |
| Accept a single change | `⌘ Y` | `Ctrl Y` |
| Reject a single change | `⌘ N` | `Ctrl N` |
| Accept all suggested changes | `⌘ ⏎` | `Ctrl ⏎` |
| Reject all suggested changes | `⌘ ⌫` | `Ctrl Backspace` |
# Database
## Overview
Qoder supports using database connections in JetBrains IDE as AI context. Through the @database feature, AI can generate SQL, perform schema analysis, or generate related code based on actual database table structures.
## Prerequisites
Before using database features, you need to configure database connections in JetBrains IDE:
1. Open the Database tool window
2. Create a database connection
3. Test if the connection is working
For detailed configuration instructions: [https://www.jetbrains.com/help/idea/database-tool-window.html](https://www.jetbrains.com/help/idea/database-tool-window.html)
## Usage
### Referencing Database in Ask/Agent Mode
**Add database to context:**
1. Click "Add Context" in the Qoder input box
2. Select @database
3. Select the target database Schema
**Note:**
- SQL files added to context are generated based on the database schema
- If a database has multiple schemas, multiple corresponding schema SQL files will be generated
After adding, you can directly ask AI database-related questions, such as:
- Generate SQL to query a specific table
- Analyze table structure design
- Generate code based on table structure
**Execute generated SQL:**
SQL code blocks returned in Ask Mode will have an execute button. Click to execute directly.
**Note:** Qoder executes SQL in the currently active database Query Console, so you need to open the corresponding database's Query Console in advance.
### Generate SQL in Query Console
1. Open the database's Query Console
2. Press `Ctrl + Shift + I`
3. Enter natural language description
4. Press Enter to generate SQL
Qoder will automatically use the current database schema as context.
### Using Slash Commands
You can create custom commands to quickly complete common operations.
**Create commands:**
1. Click the profile icon in the Qoder window
2. Select "Settings" → "Commands"
3. Create a new command
**Invoke commands:**
In the Qoder dialog, type `/` followed by the command name to invoke it. For example, type `/sql` to invoke the SQL generation command.
**Common command examples:**
Generate SQL (/sql):
```
Generate SQL statements based on current database schema
```
Database Review (/db-review):
```
Review database schema, check: naming conventions, index design, data types, table relationships
```
Generate Test Data (/mock-data):
```
Generate INSERT test data based on table structure
```
**Tip:** If a command only involves database operations (such as NL2SQL), you can add "Don't scan project files!" at the beginning to avoid scanning project files, saving tokens and avoiding ambiguity. Note that [AGENTS.md](http://AGENTS.md) and Rules files will still be included.
## Using in DataGrip
**Add Qoder to toolbar:**
1. Click the "..." icon at the top
2. Select "Qoder"
3. Click the pin icon to fix it
**Usage:**
- Click the Qoder button in Query Console
- Or press the shortcut `Ctrl + Shift + I`
Qoder will automatically select the corresponding database schema.
**Suggestion:** Add an [AGENTS.md](http://AGENTS.md) file in the project directory to describe table naming conventions, SQL guidelines, or specific data annotations and other project conventions.
## Practical Scenarios
### Database Design
#### Agent Mode (for complex scenarios)
**Suitable for:**
- Need to reference design documents
- Need to generate SQL that complies with specific specifications
- Need to generate migration scripts in specific formats (such as Flyway)
**Steps:**
1. Add relevant documents to context in Agent Mode
2. Describe requirements in natural language
3. Generate SQL file
4. Open and execute the SQL file
#### Query Console Mode (for simple scenarios)
**Suitable for:**
- Simple database structure design
- Table structure adjustments
- Minor modifications
**Steps:**
1. Open the database Schema's Query Console
2. Enter requirements
3. Adjust and execute the generated SQL
#### Database Design Best Practices
**Provide table structure examples:**
If you have standard table structure samples, you can provide them to Qoder as reference:
```
-- Table-level comment example
CREATE TABLE user_info (
id INT COMMENT 'User ID (standard field name: user_id, primary key)',
name VARCHAR(50) COMMENT 'User name (standard field name: name, real name)',
created_at DATETIME COMMENT 'Registration time (standard field name: created_at, account creation time)',
status TINYINT COMMENT 'Status (standard field name: status, enum: 0-disabled 1-normal 2-frozen)',
PRIMARY KEY (id)
) COMMENT='User basic information table | Standard table name: user_information | Business domain: User domain | Update method: Real-time';
```
**Design specification recommendations:**
Naming conventions:
- Use clear descriptive names; table and field names should directly express meaning (e.g., user, order\_item), singular form recommended
- Maintain naming consistency; uniformly use snake\_case or camelCase
- Avoid abbreviations; use customer\_address instead of cust\_addr
- Add prefixes for boolean fields, such as is\_active, has\_paid
Structure design:
- Clear primary keys; each table has a clear primary key, named id or table\_name\_id
- Clear foreign key relationships; foreign keys named like user\_id, order\_id, clearly pointing to associated tables
- Add timestamps; include created\_at, updated\_at fields
Documentation and comments:
- Add table comments explaining the table's purpose
- Add field comments explaining field meaning, value range, units, etc.
- Explain enum values; for status fields, comment on the meaning of each value
Type selection:
- Use appropriate data types; avoid using VARCHAR for everything
- Set reasonable length limits
- Clear NULL value strategy; which fields allow NULL, which are required
- Clear default values; specify if there are clear default values
### Annotating Legacy Databases
For legacy databases with non-standard naming, you can use JSON files for annotation to help AI better understand the database structure.
**Example scenario:**
Suppose there is the following legacy database table:
```
CREATE TABLE tbl_yonghu (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
xin_bie CHAR(2) NOT NULL,
nian_ling INT NOT NULL,
gonghao VARCHAR(32) NOT NULL UNIQUE,
jiru_date VARCHAR(32)
);
```
If you cannot adjust the existing database structure, you can create a `db-metadata.json` file for annotation:
```
{
"type": "database",
"description": "Database table structure annotation, use definitions here as standard",
"tables": {
"tbl_yonghu": {
"label": "User table",
"description": "Store system user information",
"required": [
"id",
"xin_bie",
"nian_ling",
"gonghao"
],
"columns": {
"id": {
"label": "User ID",
"type": "int",
"description": "Unique identifier"
},
"xin_bie": {
"label": "Gender",
"type": "char(2)",
"description": "User gender",
"enum": ["Male", "Female"]
},
"nian_ling": {
"label": "Age",
"type": "int",
"description": "User age"
},
"gonghao": {
"label": "Employee ID",
"type": "varchar(16)",
"description": "User's employee ID",
"unique": true
},
"jiru_date": {
"label": "Join date",
"type": "varchar(16)",
"description": "User's join date",
"format": "date",
"nullable": true
}
}
}
}
}
```
**Usage:**
When adding database schema to context, also add this JSON annotation file. Qoder will reference this JSON when understanding the database structure, thereby generating code and SQL more accurately.
## Notes
### Very Large Number of Database Tables
If the database schema is very large (many tables, such as in ERP, CRM scenarios), it may exceed the Agent's context limit.
**Solutions:**
- Export the database schema as multiple SQL files
- Add them to context in batches by adding files
- Only add tables relevant to the current task
### Database Dialect
Qoder automatically adds the database dialect as a comment to the database schema, so you don't need to manually declare the database type.
**If you need to manually add SQL files to context:**
- You can add comments in the SQL file to indicate the database type, for example: `-- dialect: mysql`
- You can also declare the database type in the global [AGENTS.md](http://AGENTS.md)
# Keyboard Shortcuts
Qoder Plugins on JetBrains IDEs offer a rich set of keyboard shortcuts designed to streamline your workflow. You can use them to quickly access key features like completion, Agentic Chat, and Inline chat.
## **G**eneral
| **Action** | **macOS** | **Windows/Linux** |
| :------------------- | :-------- | :---------------- |
| Open/Close Chat | `⌘ ⇧ L` | `Ctrl Shift L` |
| Open Plugin Settings | `⌘ ,` | `Ctrl Alt S` |
## **Chat**
| **Action** | **macOS** | **Windows/Linux** |
| :--------------------------- | :-------- | :---------------- |
| Submit a message | `⏎` | `⏎` |
| Insert a new line in input | `⇧ ⏎` | `Shift ⏎` |
| Add context | `@` | `@` |
| Add selected to chat | `⌘ ⌥ I` | `Ctrl Alt I` |
| Accept all suggested changes | `⌘ ⏎` | `Ctrl ⏎` |
| Reject all suggested changes | `⌘ ⌫` | `Ctrl Backspace` |
## Completion
| **Action** | **macOS** | **Windows/Linux** |
| :------------------------------ | :-------- | :---------------- |
| Accept inline suggestion | `Tab` | `Tab` |
| Discard inline suggestion | `esc` | `esc` |
| Show previous inline suggestion | `⌥ [` | `Alt [` |
| Show next inline suggestion | `⌥ ]` | `Alt ]` |
| Trigger inline suggestion | `⌥ P` | `Alt P` |
## **Inline chat**
| **Action** | **macOS** | **Windows/Linux** |
| :--------------------------- | :-------- | :---------------- |
| Open an inline chat | `⌘ ⇧ I` | `Ctrl Shift I` |
| Accept a single change | `⌘ Y` | `Ctrl Y` |
| Reject a single change | `⌘ N` | `Ctrl N` |
| Accept all suggested changes | `⌘ ⏎` | `Ctrl ⏎` |
| Reject all suggested changes | `⌘ ⌫` | `Ctrl Backspace` |
# Settings
Qoder Plugin provides two categories of settings:
- **Your Settings:** For customizing your experience with rules, MCP, and memory settings.
- **Plugin Settings:** For controlling plugin features like the response language, auto-run behavior, and updates and more.
## **Your settings**
You can access and manage your configurations by navigating to the **Your Settings** panel. To do this, open the Qoder **Chat** panel, click the dropdown menu in the top-right corner, and select **Your Settings**.
This panel allows you to view and manage the following:
- **MCP Servers:** Manage your MCP (Model Context Protocol) servers and tools. This section allows you to:
- Install new MCP tools to connect with external systems.
- Modify or remove existing server configurations as needed.
- **Memory:** This section provides insight into the memories Qoder has built based on your interactions. You can review what Qoder has learned, including:
- Your personal coding habits, coding style and more.
- Contextual information and key architectural details of the current project.
Additionally, it offers simple memory management operations, such as disabling automatic learning and clearing stored memories.
- **Rules:** Define and manage project-specific rules to guide Qoder's behavior. These rules ensure that its suggestions and actions align with your coding standards and architectural patterns. You can:
- Add multiple rules for the current project.
- Modify or delete existing rules.
- **Codebase Indexing:** Monitor and control how Qoder analyzes your project's codebase. In this section, you can:
- Check the real-time progress of codebase indexing.
- Configure which files and directories to ignore, optimizing performance and ensuring Qoder focuses only on relevant code.
## Plugin settings
The Qoder Plugin Settings panel lets you control core features like **Code Completion, NES and Agentic Chat** , as well as general options such as **HTTP proxy settings**, **update preferences**, and the AI's **response language**, etc.
You can access plugin settings of Qoder in two primary ways:
**Method 1: Via the Qoder Panel**
This method is quick and direct from the Qoder interface.
1. Open the **Qoder Chat** panel in your IDE.
2. Click the **dropdown menu** (usually a gear or three-dots icon) in the top-right corner.
3. Select **Plugin Settings**.
**Method 2: Via IDE Settings/Preferences**
This is the standard method for accessing any plugin's settings within the JetBrains environment.
1. Open the IDE's main settings dialog:
- On **macOS**: Go to `IntelliJ IDEA > Preferences...` or press `⌘ ,` .
- On **Windows/Linux**: Go to `File > Settings...` or press `Ctrl Alt S` .
2. In the left-hand panel of the settings window, find and select **Qoder**.
You can manage settings for:
- **Completion Settings:** Enable, disable, and completion length.
- **NES Settings:** Control how edit suggestions are displayed and executed.
- **Chat Settings:** Customize the Chat interface and its capabilities, like using tools, auto-run behavior and more.
- **HTTP Proxy Settings:** Configure network settings for connecting through a proxy server.
- **Updates Settings:** Enable or disable automatic updates to ensure you are always on the latest version or to manage updates manually.
- **General Settings:** Set the **preferred language for all AI-generated responses** and Display UI. Also, you are free to configure the local storage path as well.
# Overview
> An AI Coding Assistant for terminal developers: driven by natural language to autonomously read files, invoke tools, and execute commands, with permission-based confirmations before critical operations.
## What is Qoder CLI
Qoder CLI is a command-line AI Coding Assistant under the Qoder brand, bringing powerful AI coding capabilities directly to your terminal. Without leaving the command line, you can let Qoder understand your entire codebase, write and modify code, run commands, retrieve information, and complete the full development workflow from exploration to commit.
Qoder CLI is designed for developers who prefer working in the terminal. It operates in a conversational manner: you describe what you want to do in natural language, and Qoder autonomously decides which files to read, which tools to call, and which commands to execute, asking for your confirmation before critical operations based on permission settings.
## Core Capabilities
The capabilities of Qoder CLI can be broadly categorized as follows:
**Code Understanding and Generation**
- Query and edit large codebases, understanding project structure and dependencies across files.
- Support Multimodal Input (e.g., images, PDFs) to generate code from design drafts or screenshots.
- Describe bugs in natural language and let Qoder locate and fix the issues.
**Built-in Tools**
- Read, write, and edit files, and browse directories.
- Execute Shell commands.
- Search code (Grep) and find files (Glob).
- Perform Web search and Web Scraping to retrieve real-time information.
See [Built-in Tools](/cli/built-ins) for details.
**Automation and Integration**
- Automate repetitive tasks such as Git operations, commits, and PR handling.
- Connect to external services and custom tools via MCP (Model Context Protocol). See [MCP](/cli/mcp-reference) for details.
- Support Headless mode for running in scripts and CI/CD Pipelines. See [Run in Scripts](/cli/run-in-scripts) for details.
**Extensibility**
- Extend Qoder CLI's behavior to suit team needs via [Skills](/cli/builtins-reference), [Plugins](/cli/plugins-reference), [Subagents](/cli/builtins-reference), [Hooks](/cli/hooks-reference), and [Custom Commands](/cli/commands).
- Enable Qoder to remember project conventions and team knowledge through [Memory](/cli/memory) and [Knowledge Base](/cli/knowledge-base).
## How It Works
At the core of Qoder CLI is an Agent: it receives your requests, plans steps, calls tools to complete tasks, and continuously adjusts its strategy based on results along the way. The entire process revolves around four collaborative elements:
- **Agent**: Responsible for understanding intent, planning steps, and deciding the next actions.
- **Tools**: The Agent interacts with your project and environment through tools, such as reading and writing files, executing commands, and searching code.
- **Permissions**: Before executing operations with side effects (like writing files or running commands), Qoder will request confirmation or automatically allow them based on permission settings.
- **Context**: Conversation History, project instructions (`AGENTS.md`), and long-term memory together form the background information Qoder relies on to complete tasks.
For a deeper understanding of this mechanism, see [How Task Execution Works](/cli/how-it-works).
## Multiple Working Modes
The same task can be accomplished in different ways. Qoder CLI offers various working modes to cover scenarios ranging from instant conversations to long-term automation:
- **Interactive Mode**: Chat and work simultaneously; the most commonly used default mode.
- **Plan (Plan before execution)**: Analyze the problem and confirm the approach before modifying the code.
- **Goal (Continuous goal completion)**: Set completion criteria and let Qoder work continuously until the goal is achieved.
- **Scheduled Task**: Run once at a specified time, or repeatedly according to a calendar schedule.
- **/loop (Repeated execution)**: Repeatedly run the same task at fixed time intervals.
- **Headless (Run in scripts)**: Run in non-interactive environments and output structured results.
For guidance on choosing the right mode based on task characteristics, see [Choosing the Right Working Mode](/cli/working-modes).
## Use Cases
Qoder CLI is well-suited for the following typical scenarios:
- **Understanding Unfamiliar Codebases**: Quickly grasp project architecture, locate key modules, and trace call relationships.
- **Implementing Features and Fixing Bugs**: Start from requirement or bug descriptions to complete coding, testing, and verification.
- **Refactoring and Batch Modifications**: Execute consistent structural adjustments across multiple files.
- **Daily Development Automation**: Generate commit messages, review changes, handle PRs, and write tests.
- **Engineering Pipeline Integration**: Run in a non-interactive manner within CI/CD to embed AI capabilities into automated workflows.
## Next Steps
- Haven't installed it yet? Start with [Installation and Upgrade](/cli/installation).
- Already installed? Head over to [Sign-in and Authentication](/cli/authentication) to complete your account configuration.
- Want to get started right away? Follow the [Quick Start](/cli/quickstart) to complete your first task in a real project.
# Installation and Upgrade
## Requirements
Before installing Qoder CLI, ensure your environment meets the following requirements:
- **Operating System**: macOS, Linux, Windows (Windows Terminal is recommended).
- **CPU Architecture**: arm64, amd64.
- **Node.js**: Node.js >= 20.0.0 is required when installing via npm.
> Windows (arm64) is not currently supported.
## Installation
Qoder CLI offers multiple installation methods. Choose the one that best fits your environment and preferences.
### Using the Installation Script (Recommended)
The installation script automatically downloads the version matching your current system and configures the executable.
**macOS / Linux**
```shell
curl -fsSL https://qoder.com/install | bash
```
**Windows PowerShell**
```shell
irm https://qoder.com/install.ps1 | iex
```
**Windows CMD**
```shell
curl -fsSL https://qoder.com/install.cmd -o install.cmd && install.cmd
```
### Installing via npm
If you already have Node.js (>= 20.0.0) installed, you can install it globally via npm:
```shell
npm install -g @qoder-ai/qodercli
```
Specify a release channel:
```shell
# Stable version
npm install -g @qoder-ai/qodercli@latest
# Node native compatible version (beta)
npm install -g @qoder-ai/qodercli@beta
```
> `beta` is the preview channel for the Node native-compatible version, and its version number may be lower than the Stable Release. Unless you have specific needs, it is recommended to install the Stable Release.
## Verifying the Installation
After installation, run the following command. If the CLI version number is printed, the installation was successful:
```shell
qoder --version
```
If you receive a "command not found" error, check whether the installation directory has been added to the system `PATH`. For troubleshooting steps, see [Installation and Upgrade issues](/cli/troubleshoot-install).
## First Run
Run the following command in any project root directory to enter the default interactive (TUI) mode:
```shell
qoder
```
On the first run, Qoder CLI will guide you through the sign-in process. For details on sign-in methods, see [Sign-in and Authentication](/cli/authentication).
## Upgrade
Qoder CLI has Auto-Upgrade enabled by default. You can also manually upgrade to the latest version at any time.
### Upgrading via the Installation Script
**macOS / Linux**
```shell
curl -fsSL https://qoder.com/install | bash -s -- --force
```
**Windows PowerShell**
```shell
irm https://qoder.com/install.ps1 | iex
```
**Windows CMD**
```shell
curl -fsSL https://qoder.com/install.cmd -o install.cmd && install.cmd
```
### Using the Built-in Update Command
```shell
qoder update
```
### Upgrading via npm
```shell
npm install -g @qoder-ai/qodercli@latest
```
## Auto-Upgrade Settings
Auto-Upgrade is enabled by default. To disable it, set `general.enableAutoUpdate` to `false` in `~/.qoder/settings.json`:
```json
{
"general": {
"enableAutoUpdate": false
}
}
```
For the scope and application order of configuration files, see [Configuration files and application order](/cli/settings).
## Uninstallation
The uninstallation method depends on how you installed it:
- **Installed via npm**: Run `npm uninstall -g @qoder-ai/qodercli`.
- **Installed via the installation script**: Delete the executable placed by the installation script and remove the corresponding directory from `PATH`.
If you also want to clean up configuration and local data, you can delete the configuration directory (default: `~/.qoder`). Before deleting, ensure there are no sessions, memories, or settings you need to keep.
> The configuration directory location can be customized via the `QODER_CONFIG_DIR` Environment Variable, with the default being `~/.qoder`. If you have set this variable, delete the corresponding directory.
# Sign-in and Authentication
## Overview
Authentication is required before using Qoder. When you run a command for the first time, Qoder CLI will automatically prompt you to sign in.
Qoder CLI uses Qoder's proprietary authentication system, which primarily offers two authentication methods:
- **Interactive Sign in (Recommended)**: Sign in via a browser or by pasting a token in the terminal. Ideal for daily local use.
- **Environment Variable**: Authenticate using a Personal Access Token. Suitable for CI/CD pipelines and headless automation environments.
## Interactive Sign in
Launch Qoder CLI in the terminal, then enter `/login` at the interactive prompt:
```shell
# Start Qoder CLI in the terminal
qoder
# At the interactive prompt, enter /login
/login
```
Then, select your preferred sign-in method:
- **Login with Qoder Platform (Browser)**: Opens a browser window to authenticate using your Qoder account.
- **Use Qoder Personal Access Token (QODER\_PERSONAL\_ACCESS\_TOKEN)**: Sets the `QODER_PERSONAL_ACCESS_TOKEN` environment variable using a token generated in your Qoder settings.
After making your selection, Qoder CLI will guide you through the remaining steps.
> `/login` You can also use the alias `/signin`.
### When the Browser Cannot Be Opened Automatically
In environments without a graphical interface, Qoder CLI automatically skips launching the browser, and the sign-in screen prints the sign-in URL directly—manually copy it into a browser to complete authentication. An environment is treated as having no graphical interface if any of the following conditions is met:
- `CI` is set;
- `BROWSER=www-browser`;
- `DEBIAN_FRONTEND=noninteractive`;
- inside an SSH session (`SSH_CONNECTION`);
- on Linux with none of `DISPLAY`, `WAYLAND_DISPLAY`, or `MIR_SOCKET` set.
Therefore, no extra configuration is needed on remote servers, in containers, or in CI environments. If the browser fails to open, you can likewise manually copy the URL printed on the screen.
### Automatic Token Refresh
After signing in via the browser, Qoder CLI automatically refreshes the token in the background, so you don't need to manually sign in again for daily use.
## Using a Personal Access Token
For non-interactive sessions or automated environments (such as CI/CD pipelines), you can authenticate using a Personal Access Token (PAT).
### Obtaining a Token
Create and manage your Personal Access Token on the following page:
> [https://qoder.com/account/integrations](https://qoder.com/account/integrations)
### Authenticating via Environment Variables
Set the token in the `QODER_PERSONAL_ACCESS_TOKEN` environment variable:
```shell
# Linux / macOS example
export QODER_PERSONAL_ACCESS_TOKEN="your_personal_access_token_here"
```
```shell
# Windows example (Command Prompt). Do not use quotes, as CMD will include them in the variable value
set QODER_PERSONAL_ACCESS_TOKEN=your_personal_access_token_here
```
```shell
# Windows example (PowerShell)
$env:QODER_PERSONAL_ACCESS_TOKEN="your_personal_access_token_here"
```
Once set, Qoder CLI will automatically use the PAT for authentication.
> If you have both set the `QODER_PERSONAL_ACCESS_TOKEN` environment variable and signed in via `/login`, authentication **uses the PAT from the environment variable first**; to use the credentials saved by `/login`, you must clear this environment variable first.
## Authentication-Related Environment Variables
| Environment Variable | Description |
| :---------------------------- | :--------------------------------------------------------------------- |
| `QODER_PERSONAL_ACCESS_TOKEN` | Personal Access Token. Automatically uses PAT authentication when set. |
| `QODER_CONFIG_DIR` | Custom configuration directory. Defaults to `~/.qoder`. |
## Checking Authentication Status
Enter `/status` in an interactive session to open the status panel, which includes two tabs: Usage and Status. The Usage tab displays the API quota and token usage for the current session (plan type, quota usage, session duration, total code changes, etc.), while the Status tab shows the current CLI status information. This is the most direct entry point for troubleshooting if you suspect an authentication issue.
## Sign out
When you need to sign out of Qoder, enter `/logout` at the interactive prompt:
```shell
# At the interactive prompt, enter /logout
/logout
```
> `/logout` You can also use the alias `/signout`, which will prompt for confirmation before signing out.
If you authenticated using the `QODER_PERSONAL_ACCESS_TOKEN` environment variable, you must clear this environment variable before running `/logout`. Otherwise, the next startup will automatically sign in using that token again.
## Troubleshooting
- **Browser did not open automatically**: In environments without a graphical interface, Qoder CLI automatically skips launching the browser; manually copy the URL printed on the sign-in screen and open it in a browser.
- **Sign-in callback failed or timed out**: Ensure your local network can access Qoder services. Check your proxy settings if necessary. See [Network, Proxy, and VPC](/cli/network).
- **PAT is invalid or expired**: Go to the account integration page to regenerate the token and update `QODER_PERSONAL_ACCESS_TOKEN`.
For more troubleshooting steps, see [Sign-in and Authentication Issues](/cli/troubleshoot-auth).
# Quick Start
> Complete your first task in 10 minutes: launch Qoder CLI, understand the project, make a small change, and commit it.
## Prerequisites
- **Qoder CLI installed**: Running `qoder --version` should print the version number. If not yet installed, see [Installation and Upgrade](/cli/installation).
- **Signed in**: You will be automatically guided through the sign-in process the first time you run `qoder`. For details on sign-in methods, see [Sign-in and Authentication](/cli/authentication).
## Start
Navigate to your project root directory and launch the default interactive (TUI) mode:
```shell
cd /path/to/your-project
qoder
```
Once you see the conversation prompt `>`, simply describe what you want to do in natural language.
## Complete Your First Task
### Step 1: Let Qoder Understand the Project
Start with an exploratory question:
```text
Help me outline the overall architecture and main modules of this project
```
Qoder will autonomously search and read relevant files, providing explanations along with file locations. You can follow up on its answers to dive deeper.
> It is recommended to enter `/init` to generate a `AGENTS.md` memory file in your project, allowing Qoder to remember project conventions in subsequent sessions. See [Memory](/cli/memory) for details.
### Step 2: Make a Small Change
Describe a specific, small task in natural language, for example:
```text
Add a unit test for and run it to verify
```
Before executing operations with side effects (such as writing files or running shell commands), Qoder will ask for your confirmation based on permission settings. For details on the confirmation mechanism and allow rules, see [Permissions](/cli/permissions).
### Step 3: Review and Commit
Once the changes are complete, enter `/review` to have Qoder review the local code changes. After confirming everything is correct, simply ask it to commit:
```text
Help me generate a commit message and commit this change
```
For more prompt examples for daily tasks (exploring code, fixing bugs, refactoring, handling PRs, etc.), see [Common Development Tasks](/cli/common-tasks).
## Quick Reference
| Input | Action |
| :-------- | :------------------------------------------------- |
| `!` | Bash Mode: run shell commands directly |
| `/` | Open the slash commands list |
| `/help` | Display TUI help |
| `/status` | View version, model, account, and API Connectivity |
| `/usage` | View Credits usage |
| `/resume` | View and resume historical sessions |
| `/quit` | Exit TUI |
For complete input modes, slash commands, and startup arguments, see [Run Tasks](/cli/run-tasks).
## Next Steps
- Learn about interaction methods and startup arguments: [Run Tasks](/cli/run-tasks).
- Find prompts by task scenario: [Common Development Tasks](/cli/common-tasks).
- Explore more working modes like Plan, Goal, and Scheduled Tasks: [Choosing the Right Working Mode](/cli/working-modes).
# How Task Execution Works
## Overview
Understanding how Qoder CLI works helps you better predict its behavior, write more effective prompts, and properly control and correct it when needed.
At its core, Qoder CLI is an **Agent**: it receives your requests, understands the intent, plans the steps, calls tools to interact with your project and environment, and continuously adjusts its strategy based on the results of each step until the task is complete. The entire process is driven by the collaboration of four core elements: the Agent, tools, permissions, and context.
## Agent Main Loop
When Qoder CLI processes a request, it generally goes through the following loop:
1. **Receive request**: Reads your input and combines it with the current context (Conversation History, project instructions, Memory) to understand what you want to achieve.
2. **Plan the next step**: The model decides what to do next—whether to read a file to understand the current state, search the codebase, make direct modifications, or run a command for verification.
3. **Call tools**: The Agent executes specific actions through tools, such as reading files, editing code, executing shell commands, searching code, or retrieving web pages.
4. **Observe results**: Incorporates the results returned by the tools back into the context.
5. **Continue or finish**: Determines whether the task is complete based on the results. If not, it returns to step 2 to plan the next step; if complete, it provides a summary.
This loop repeats for multiple turns until the task is completed, the maximum number of turns is reached, or you manually interrupt it. Because it is a loop rather than a one-shot generation, Qoder can handle complex tasks that require multiple steps, cross-file operations, and continuous verification during execution.
> You can use `--max-turns` to limit the maximum number of Conversation Turns for a single run, preventing infinite loops in automated scenarios.
## Tools
The Agent itself is only responsible for thinking and decision-making; all actual operations on the external world are performed through **tools**. Qoder CLI includes a set of commonly used Built-in Tools:
- **File operations**: Read, write, and edit files, and browse directories.
- **Execution**: Run shell commands.
- **Search**: Search code by content (Grep) and find files by name (Glob).
- **Information**: Web search and Web Scraping.
In addition to built-in tools, you can integrate external tools via [MCP](/cli/mcp-reference), and extend the Agent's capabilities through [Skills](/cli/builtins-reference) and [Subagents](/cli/builtins-reference). For a complete list of tools, their purposes, and limitations, see [Built-in Tools](/cli/built-ins).
## Permissions
Tool calls may have side effects—modifying files, running commands, or accessing the network. To ensure you always remain in control, Qoder performs a permission check **before every tool call**. The outcome falls into one of three categories:
- **allow**: Execute the tool immediately.
- **ask**: Require confirmation before execution.
- **deny**: Block the call.
The specific behavior of permissions is determined by the **permission mode**. For example, in the default mode, safe read operations are executed automatically, while sensitive operations require confirmation; in more automated modes, more operations are automatically allowed.
Different runtime environments handle `ask` differently: an interactive terminal will prompt you for confirmation, non-interactive (Headless) mode will convert `ask` to a denial, and SDK and IDE integrations will delegate the decision to the Host Program.
For a complete explanation of permission modes, rule configurations, and directory trust, see [Permissions](/cli/permissions).
## Context
Qoder reconstructs the context for each session. The background information it relies on for decision-making primarily comes from three levels:
- **Conversation Context**: Historical messages, tool calls, and results within the current session. As the conversation progresses, the context continuously accumulates.
- **Project instructions**: Static memory maintained by you or your team, such as `AGENTS.md` and rules, which describe the project structure, development standards, and collaboration conventions.
- **Long-term memory**: Information retained across sessions, including team conventions and optional Auto-Memory.
The context window is limited. When a conversation becomes very long, Qoder manages the context through mechanisms like Compact. For the differences and collaboration methods among these three, see [How Memory Works](/cli/how-memory-works).
## Different Working Modes
The above describes the most basic interactive loop. For different tasks, Qoder CLI also offers various working modes: Plan for planning before execution, Goal for continuously achieving objectives, Scheduled Tasks, /loop for repeating at intervals, Workflow for multi-Agent collaboration, and Headless Mode for scripts. For guidance on how to choose, see [Choosing the Right Working Mode](/cli/working-modes).
# Choose a Working Mode
## Overview
The same task can be accomplished in different ways. Qoder CLI offers various working modes, covering scenarios from instant conversations to long-running automation. Choosing the right mode helps you strike the perfect balance between controlling every step and letting Qoder work autonomously.
This document helps you quickly choose the right approach based on task characteristics. Each mode has its own detailed documentation, which you can click to explore.
## Quick Guide
- Want to chat and work simultaneously, intervening at any time → **interactive mode**
- Want to review the plan and confirm before making changes → **Plan**
- Have a clear goal and want Qoder to work until it's done → **Goal**
- Need to run at a specific time or repeat on a calendar schedule → **Scheduled Task**
- Need to repeatedly run the same task at fixed time intervals → **/loop**
- Need multiple agents to collaborate and orchestrate complex processes → **Workflow**
- Need to run automatically in scripts or CI/CD pipelines → **Headless**
## Work as You Chat: Interactive Mode
Interactive mode is the most commonly used default approach. Run `qoder` in the project root directory to enter an interactive (TUI) session. You can converse in natural language, monitor Qoder's actions in real time, confirm permissions, and adjust the direction as needed.
It is ideal for tasks requiring close human-AI collaboration, such as exploring code, implementing features step-by-step, and debugging issues. For more details, see [Run Tasks](/cli/run-tasks).
## Plan Before Execution: Plan
Use Plan when tasks are complex, have a broad impact, or when you want to review the approach before taking action. After entering Plan mode, Qoder explores the code in read-only mode and outputs a plan without directly modifying the code. Once you confirm the plan, exit Plan mode to begin execution.
Use the `/plan` command to enter or exit. For more details, see [Plan Before Execution (Plan)](/cli/plan-mode).
## Continuously Achieve a Goal: Goal
Use Goal when you have a clear completion condition and want Qoder to work autonomously until it is achieved. Enter via `/goal set `, and Qoder will automatically switch to an automated execution state, minimizing interruptions along the way.
It is suitable for tasks with a clear endpoint, such as "fixing all failing tests" or "completing a refactoring until the build passes." For more details, see [Continuously Achieve a Goal (Goal)](/cli/goal).
## Execute at a Specified Time: Scheduled Task
Use Scheduled Tasks when a task needs to run once at a future point in time or repeat according to a calendar schedule. This is ideal for scheduled inspections, periodic reports, and automation triggered by a schedule.
For more details, see [Scheduled Execution Task](/cli/scheduled-tasks).
## Repeat at Fixed Intervals: /loop
Use `/loop` when you need to repeatedly run the same task at fixed time intervals. This is suitable for polling status, continuous checking, and periodic repetitive actions.
For more details, see [Repeat Tasks (/loop)](/cli/loop).
## Multi-Agent Collaboration: Workflow
When a task is complex enough to require division of labor and collaboration among multiple agents, you can orchestrate a workflow to break the task down and assign it to different subagents. This is ideal for decomposing and advancing large tasks in parallel.
For creating and orchestrating subagents, see [Subagent](/cli/builtins-reference). For multi-agent orchestration, see [Dynamic workflows](/cli/built-ins). For parallel collaboration, see [Parallel Processing of Multiple Tasks](/cli/parallel-tasks).
## Run in Scripts: Headless
Use Headless (non-interactive) mode when you need to embed Qoder CLI into scripts, automation processes, or CI/CD pipelines. Run it via `qoder --print` to output structured results in Text, JSON, or Stream JSON format.
Since there is no one present to confirm actions, permissions must be pre-configured in Headless mode. For more details, see [Run in Scripts](/cli/run-in-scripts).
## Combining Approaches
These working modes are not mutually exclusive and can be combined. For example:
- First use **Plan** to confirm the approach, then enter **Goal** to let Qoder execute autonomously until completion.
- Pair **Headless** mode with permission modes to achieve unattended yet controlled automation.
- Use **Scheduled Task** or **/loop** to trigger a fixed automation process.
Start with the approach that best fits your needs, and gradually combine them into workflows tailored for your team as you become more familiar with Qoder.
# Configuration Scope
## Overview
Qoder CLI configuration is divided into three scopes: **personal**, **project**, and **local**. Understanding what each scope is best suited for helps you place settings in the right location—ensuring you don't inadvertently impose personal preferences on the team or scatter team conventions across individual machines.
The three scopes correspond to three different files:
| Scope | File | Suitable Content | Committed with Project |
| :------- | :------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- | :--------------------- |
| Personal | `~/.qoder/settings.json` | Personal preferences across all projects, such as themes, UI, and personal default models | No |
| Project | `/.qoder/settings.json` | Team-shared project conventions, such as permission rules and project-level model selection | Yes |
| Local | `/.qoder/settings.local.json` | Project-specific private settings on the current machine, such as local service addresses and personal temporary overrides | No |
> For how configuration items are merged layer by layer and the order of precedence, see [Configuration Files and Application Order](/cli/settings).
## Personal Configuration
Personal configuration is stored in `~/.qoder/settings.json` under the User Configuration Directory and applies to **every project** you open. It is ideal for personal preferences that are unrelated to specific projects:
- UI preferences such as interface themes, status bar, and keyboard shortcuts.
- Personal default models and reasoning effort.
- User-level toggles such as auto-upgrade.
Personal configuration belongs solely to you and is not distributed to the team via the project repository.
## Project Configuration
Project configuration is stored in `/.qoder/settings.json` at the project root directory. It applies only to this project and is **suitable for committing to the version control repository** to share with the team. It is ideal for conventions the team wishes to unify:
- Permission rules and Directory Trust Policies.
- Unified model selection or parameters for the project.
- Project-level extension configurations (MCP, Hooks, etc.).
Once these settings are committed to the repository, team members will automatically apply the same conventions when using Qoder CLI in this project.
## Local Configuration
Local configuration is stored in `/.qoder/settings.local.json` at the project root directory. It applies only to this project and only on the **current machine**. It is ideal for private settings that you do not want to commit or affect others:
- Local service addresses and personal test data.
- Personal temporary overrides for project configuration.
Local configuration **should not be committed** to the version control repository. Typically, `.qoder/settings.local.json` should be added to `.gitignore`.
## .qoder Directory Structure
In addition to configuration files, the `.qoder/` directory at the project root directory also hosts various local data and extensions for Qoder CLI runtime. Common contents include:
```text
/.qoder/
├── settings.json # Project-level configuration (committable)
├── settings.local.json # Local project configuration (not committed)
├── rules/ # Project-level rule files (*.md)
├── skills/ # Project-level skills
├── worktrees/ # Isolated worktrees created by --worktree
└── scheduled_tasks.json # Scheduled task definitions
```
Among them:
- Rule files split by topic under `rules/`, see [Memory](/cli/memory).
- Project-level Skills under `skills/`, see [Skills](/cli/builtins-reference).
- Isolated checkouts created by `--worktree` under `worktrees/`, see [Run Tasks](/cli/run-tasks) and [Handling Multiple Tasks in Parallel](/cli/parallel-tasks).
- Scheduled tasks saved in `scheduled_tasks.json`, see [Scheduled Execution Task](/cli/scheduled-tasks).
User-level data (such as `settings.json`, authentication status, and plugins) is stored in the User Configuration Directory, which defaults to `~/.qoder`.
> The location of the User Configuration Directory can be customized via the `QODER_CONFIG_DIR` Environment Variable. The project-level `.qoder` directory is always located at the project root directory.
## How to Choose
When placing configurations, consider the following sequence:
1. Is this a personal preference you want **across all projects**? → Put it in personal configuration.
2. Is this a project convention the **team should unify**? → Put it in project configuration and commit it to the repository.
3. Is this a project setting **only on my machine** that you don't want to affect others? → Put it in local configuration and add it to `.gitignore`.
When the same configuration item appears in multiple scopes, it will be merged and overridden according to the precedence order. For detailed rules, see [Configuration Files and Application Order](/cli/settings).
# How Memory Works
## Overview
Qoder CLI **reconstructs the context** for every session—it does not automatically remember what was discussed in the previous session unless that information is explicitly saved. Understanding the mechanisms Qoder uses to retain information helps you solidify knowledge that should be kept long-term, while preventing irrelevant content from filling up the context.
The information Qoder relies on primarily comes from three levels, each with different lifecycles and purposes:
| Level | Lifecycle | Maintained By | Typical Content |
| :------------------- | :----------------------- | :-------------------------------------- | :--------------------------------------------------------------- |
| Conversation Context | Current session | Automatically accumulated by Qoder | Historical messages, tool calls, results |
| Project Instructions | Long-term, per project | You or your team | `AGENTS.md`, rules |
| Long-Term Memory | Long-term, cross-session | Team conventions + optional Auto-Memory | Preferences, project background, locations of external resources |
## Conversation Context
Conversation context is the accumulated history within the current session—your inputs, Qoder's responses, and every tool call along with its results. It allows Qoder to maintain coherence within a single session, remembering what you discussed just a few minutes ago.
Conversation context has several key characteristics:
- **Session-scoped**: It only exists within the current session. When you start a new session, the previous conversation context is not automatically carried over.
- **Limited capacity**: The context window is finite. The longer the conversation, the more space it consumes.
- **Manageable**: You can proactively clear or compact the context.
### Managing Conversation Context
- **`/clear`**: Clears the conversation history context and starts a new session, allowing you to "start from scratch." This is useful when switching to a completely unrelated new task.
- **`/compact`**: Summarizes and compacts the current session's historical context into a more concise form, freeing up context space while retaining key information. Ideal for long sessions when the context starts getting tight.
When a conversation is long and context pressure is high, Qoder will also compact it when necessary. For related performance and context troubleshooting, see [Performance, Context, and Long Session Issues](/cli/troubleshoot-performance).
## Project Instructions
Project instructions are static memory **explicitly written** by you or your team to tell Qoder about the project's structure, development standards, and collaboration conventions. They are provided to the model as context in every session, ensuring Qoder adheres to team conventions.
There are two main forms:
- **`AGENTS.md`**: The default context file name for Qoder CLI, suitable for hosting overall project instructions and stable conventions. Common locations include user-level `~/.qoder/AGENTS.md`, project-level `/AGENTS.md`, and local project-level `/AGENTS.local.md`.
- **Rules**: Markdown rule files placed under `/.qoder/rules/`, split by topic or file scope, suitable for replacing a single bloated `AGENTS.md`.
You can run `/init` in your project to automatically generate `AGENTS.md`, or use `/memory` to manage memory files at various levels. For full details, see [Memory](/cli/memory).
> Project instructions are context provided to the model, not enforced policies. If you need to **strictly** block certain commands, tools, or paths, use [Permissions](/cli/permissions) or [Hooks](/cli/hooks-reference).
## Long-Term Memory
Long-term memory is information retained across sessions. In addition to the static memory maintained by the team mentioned above (`AGENTS.md`, rules), Qoder CLI also supports **Auto-Memory**: when enabled, Qoder saves information learned from conversations that remains useful later into local Markdown memory files, such as your preferences, feedback, project background, and the locations of external reference materials.
Entry points for viewing and managing Auto-Memory:
- Open the auto-memory folder in the `/memory` panel.
- Run `/memory manage` to manage automatically saved topic files.
Auto-Memory is also provided to the model as context, helping Qoder carry forward previously accumulated understanding in new sessions. See [Memory](/cli/memory) for details.
## How They Work Together
At the start of a session, Qoder loads the applicable project instructions and long-term memory, injecting them into the context as background; as the conversation progresses, the conversation context continuously accumulates. Together, these three form the complete background Qoder relies on when making decisions:
- **Conversation context** addresses "where we are in this session."
- **Project instructions** address "what conventions must be followed in this project."
- **Long-term memory** addresses "what preferences and background should be remembered across sessions."
To make a piece of knowledge effective long-term, write it into project instructions or save it as long-term memory; keep temporary information relevant only to the current task in the conversation context, and clean it up with `/clear` or `/compact` when necessary.
# Run Tasks
## TUI mode
Run `qoder` in any project root directory to enter the default TUI (interactive) mode. You can converse with the CLI via text or execute specific functions using slash commands.
### Input Modes
The TUI provides multiple input modes:
| Command | Description |
| :------ | :--------------------------------------------------------------------- |
| `>` | Dialog mode (default). Enter any text to converse with the CLI |
| `!` | Bash Mode. Enter `!` in dialog mode to directly run shell commands |
| `/` | Slash mode. Enter `/` in dialog mode to open and run built-in commands |
| `\` `⏎` | Press Enter to start multiline input |
### Built-in Tools
Qoder CLI includes built-in tools such as Grep, Read, Write, and Bash for file/directory operations and shell command execution.
For details on tool capabilities and control methods, see [Tools](/cli/built-ins).
### Slash commands
Quickly access features and settings using the following built-in slash commands:
| Command | Description |
| :--------------- | :------------------------------------------------------------------------------------------------------------------- |
| `/login` | Sign in to your Qoder account |
| `/help` | Display TUI help |
| `/init` | Initialize or update the `AGENTS.md` memory file in the project |
| `/memory` | Open Memory Overview to manage user-level, project-level, and local memory, as well as Auto-Memory entries |
| `/quest` | Intelligent workflow orchestrator that guides you through feature development step-by-step using dedicated subagents |
| `/review` | Review local code changes |
| `/resume` | View and restore sessions |
| `/clear` | Clear the historical context of the current session |
| `/compact` | Summarize the historical context of the current session |
| `/usage` | Display current Credits usage |
| `/status` | View CLI status, including version, model, account, API Connectivity, tool status, etc. |
| `/config` | View Qoder CLI system configuration |
| `/effort` | Adjust the thinking depth and related Model Parameters for the current model |
| `/agents` | Subagent commands: view, create, and manage subagents |
| `/tasks` | View currently running background tasks |
| `/release-notes` | Display the Qoder CLI changelog |
| `/vim` | Toggle Vim edit mode |
| `/feedback` | Send feedback related to Qoder CLI |
| `/quit` | Exit the TUI |
| `/logout` | Sign out of your Qoder account |
### Advanced Startup Options
When starting the CLI, you can use the following options to control its behavior:
| Command | Description | Example |
| :------------------- | :------------------------------------------------------------------------------- | :-------------------------------------------- |
| `-w` | Specify the working directory | `qoder -w /Users/demo/projects/nacos` |
| `-c` | Resume the last session | `qoder -c` |
| `-r` | Restore a specific session | `qoder -r *******-c09a-40a9-82a7-a565413fa39` |
| `--allowed-tools` | Allow only specified tools | `qoder --allowed-tools=Read,Write` |
| `--disallowed-tools` | Deny specified tools | `qoder --disallowed-tools=Read,Write` |
| `--tools` | Restrict available built-in tools (`""` to disable all, `default` to enable all) | `qoder --tools=Read,Edit -p "Fix login"` |
| `--max-turns` | Maximum conversation turns | `qoder --max-turns=10` |
| `--worktree [name]` | Start in an isolated git worktree | `qoder --worktree feature-a` |
| `--yolo` | Skip permission checks | `qoder --yolo` |
For permission-related startup arguments and settings, see [Permissions](/cli/permissions).
## Print mode
Print mode is a non-interactive mode. Run `qoder --print` to enter it, and the output will be printed in the format specified by the `--output-format` parameter.
### Parameters
Global parameters can be used with any command:
| Parameter | Description | Example |
| :-------------------- | :------------------------------------- | :----------------------------------------------- |
| `-p` | Run the agent non-interactively | `qoder -p hi` |
| `-o, --output-format` | Output format: text, JSON, stream-json | `qoder --output-format=json` |
| `-w` | Specify the working directory | `qoder -w /Users/qoder_user/projects/qoder_demo` |
| `-c` | Resume the last session | `qoder -c` |
| `-r` | Restore a specific session | `qoder -r ********-c09a-40a9-82a7-a565413fa393` |
| `--allowed-tools` | Allow only specified tools | `qoder --allowed-tools=Read,Write` |
| `--disallowed-tools` | Deny specified tools | `qoder --disallowed-tools=Read,Write` |
| `--max-turns` | Maximum conversation turns | `qoder --max-turns=10` |
| `--worktree [name]` | Start in an isolated git worktree | `qoder --worktree feature-a -p "Fix login"` |
| `--yolo` | Skip permission checks | `qoder --yolo` |
## Worktree
Using `--worktree [name]` allows you to start a Qoder CLI session in an isolated git worktree. This is ideal for handling multiple tasks in parallel within the same repository, preventing multiple sessions from sharing the same working directory or altering the main checkout.
> Requirement: Run this command in a Git repository and ensure Git is installed locally.
### Starting in a worktree
```shell
qoder --worktree feature-a
qoder --worktree feature-a "Implement the login fix"
qoder --worktree
```
If no worktree name is provided, Qoder CLI will automatically generate one. A worktree name can be up to 256 characters long and may contain letters, numbers, dots, underscores, hyphens, and segments separated by `/`. Names containing `/` will be converted to `+` in both directory and branch names.
When creating a new named worktree, Qoder CLI places it under `/.qoder/worktrees/` and creates a temporary branch named `worktree-`. If a worktree with the same name already exists, Qoder CLI reuses that directory directly instead of creating a new one.
The new worktree is preferably created based on the default branch reference pointed to by the local `origin/HEAD`. If `origin/HEAD` is not configured, Qoder CLI will use `origin/main` if it can be resolved or fetched; otherwise, it falls back to the current `HEAD`. If you must start from the latest remote commit, execute `git fetch origin` first.
### Copying Local Files
A new worktree is a clean checkout and does not include untracked files like `.env` by default. To copy local files to the new worktree, add `.worktreeinclude` in the repository root:
```text
.env
.env.local
config/secrets.json
```
Only files that match `.worktreeinclude` and are already ignored by Git will be copied. The local project-level setting `.qoder/settings.local.json` is automatically copied if it exists.
### Resuming and Cleaning Up
When the session ends, Qoder CLI prints the worktree path and the command to resume the session:
```shell
cd && qoder --resume
```
An interactive exit checks for uncommitted files and new commits in the worktree. A clean worktree can be deleted automatically; if local files or commits exist, the exit prompt will ask you to choose whether to keep or delete them. Deletion discards these changes and removes the temporary branch.
To manually delete a worktree, run:
```shell
git worktree remove
```
If the `worktree-` branch is no longer needed, you can delete it separately:
```shell
git branch -d worktree-
```
### Using worktrees in a session
In an existing session, you can also ask Qoder CLI to handle tasks in an isolated worktree. It will create and enter a worktree for the current session; when you need to leave, you can ask it to exit the worktree and restore the original working directory.
Subagents can also use worktree isolation. When a Markdown Subagent needs to modify files in an isolated checkout, add `isolation: worktree` to its definition. A clean subagent worktree is deleted after the subagent finishes; worktrees with changes are retained. See [Subagent](/cli/builtins-reference) for configuration details.
For worktrees created during a session and subagents with worktree isolation enabled, the `WorktreeCreate` hook can provide a custom worktree path. See [Hooks](/cli/hooks-reference) for the accompanying `WorktreeRemove` cleanup behavior. The `--worktree` startup argument itself requires usage within a Git repository and uses Git to create the worktree.
If you need full manual control over directories and branches, you can directly use Git to create a worktree and then start Qoder CLI in that directory:
```shell
git worktree add ../project-feature-a -b feature-a
cd ../project-feature-a && qoder
```
## Memory
Qoder CLI retains context across sessions using `AGENTS.md` files and optional Auto-Memory. Commonly used files include the user-level `~/.qoder/AGENTS.md`, project-level `${project}/AGENTS.md`, and local project-level `${project}/AGENTS.local.md`.
### Automatic Generation
Start the TUI in the target project and enter `/init` to generate `AGENTS.md` in the project directory.
### Manual Management
- Create `AGENTS.md` in the project and edit its contents.
- Enter `/memory` in the TUI to manage user-level, project-level, and local memory files.
- When Auto-Memory is enabled, you can open the auto-memory folder in the `/memory` panel, or enter `/memory manage` to manage automatically saved memory files.
For complete instructions, see [Memory](/cli/memory).
# Common Development Tasks
## Overview
This document summarizes common practices for handling daily development tasks with Qoder CLI—from exploring unfamiliar code, fixing bugs, and refactoring, to writing tests, committing, and reviewing. Each category provides ready-to-use prompt examples that you can adapt to your own projects.
All examples are performed in interactive mode. For startup instructions, see [Run Tasks](/cli/run-tasks).
## Exploring and Understanding Code
When facing an unfamiliar codebase, start by having Qoder help you build a high-level understanding:
```text
Help me outline the overall architecture and main modules of this project.
Where is this feature implemented? Which files are involved?
Starting from the entry point, explain clearly how a request is processed.
Where is this function called from?
```
Qoder will autonomously search the code, read relevant files, and provide explanations with file locations. You can follow up on its responses to dive deeper step by step.
## Fixing Bugs
Describe the symptoms and let Qoder locate and fix the issue:
```text
Why is this test failing? Help me fix it.
Run npm test, find the cause of the error, and fix it.
This API occasionally throws errors under concurrent load, help me troubleshoot it.
```
A safe approach is to have Qoder reproduce the issue and explain the root cause before making any changes. For issues with a broader impact, you can use Plan to confirm the approach first; see [Plan Before Execution (Plan)](/cli/plan-mode).
## Refactoring
Refactoring often involves multiple files. Clearly describe your goals and constraints:
```text
Extract the date handling functions in utils into a separate module and update all references
Unify the error handling approach in this directory while keeping the external behavior unchanged
Refactor these callbacks to use async/await, making sure not to change the underlying logic
```
It is recommended to run tests and perform a code review before and after refactoring to ensure behavior remains unchanged; see [Viewing and Reviewing Code Changes](/cli/review-changes). For larger-scale refactoring, it is best to use Plan to outline the approach first.
## Implementing Features
Let Qoder write code based on your requirements:
```text
Implement an Express middleware for request rate limiting
Complete the corresponding client methods according to this API documentation
Add form validation and error messages to this page
```
Qoder supports multimodal input. You can attach design mockups or screenshots and have it generate code accordingly.
## Writing and Running Tests
```text
Add unit tests to this module, covering the main branches
Write a regression test for the recent changes
Run the tests and fix the failing cases
```
Having Qoder proactively run tests after writing code creates a closed loop of implementation, verification, and correction. To have it continuously fix issues until all tests pass, you can use Goal; see [Continuously Achieving Goals (Goal)](/cli/goal).
## Commits and PRs
```text
Generate a commit message for these changes
Split the related changes into multiple semantically clear commits
Summarize the changes in this branch compared to main, and write a PR description
```
When performing Git operations, Qoder will request confirmation before execution based on your permission settings. For details on permission control, see [Permissions](/cli/permissions).
## Code Review
Review your changes before committing:
```text
Review my current changes and identify potential issues
Compare with the main branch and review this feature branch
```
You can also directly use `/review` to select the scope of the review; see [Viewing and Reviewing Code Changes](/cli/review-changes).
## Tips
- **Clearly describe goals and constraints**: Specifying what you want and what you do not want changed can significantly improve the quality of the results.
- **Focus on one thing at a time**: Breaking complex tasks into steps is more manageable than describing all requirements at once.
- **Leverage project instructions**: Document your project conventions in `AGENTS.md`, and Qoder will follow them in every session; see [Memory](/cli/memory).
- **Large Codebases**: For practices tailored to large repositories and Monorepos, see [Best Practices for Large Codebases](/cli/best-practices).
# Plan First, Then Execute
## Overview
Plan allows Qoder to explore the codebase in read-only mode, analyze problems, and propose a solution before making any code changes. Once you approve the plan, you can exit Plan mode to proceed with the actual modifications. It is ideal for tasks with a broad impact, those involving multiple files, or situations where you want to review the overall approach before any changes are made.
Plan is an independent **working state**, not a permission policy—it can coexist with any permission mode. When in Plan mode, Qoder's write access is restricted, and its primary output is a proposed plan.
## Entering and Exiting
Use the `/plan` command to toggle Plan mode on or off:
```shell
/plan
```
- Once enabled, Qoder will explore the code in read-only mode and output a plan without directly modifying your code.
- Run `/plan` again to exit.
You can also enter the Plan working state at startup:
```shell
qoder --permission-mode plan
```
> `--permission-mode plan` is retained for backward compatibility. Since Plan is a working state rather than a permission mode, this value is mapped to "default permission mode + enter Plan state".
### Confirmation on entering and exiting
When Qoder itself proposes entering or leaving Plan, it asks you to confirm first — in every permission mode, including YOLO and Auto. Approving a plan is a decision about how the session should proceed rather than a risk a permission mode can weigh on your behalf, and the exit dialog is where the plan itself gets accepted. Toggling Plan yourself with `/plan` needs no confirmation.
If you never want Plan to interrupt a YOLO or Auto session, turn it off in settings:
```json
{
"general": {
"plan": {
"enabled": false
}
}
}
```
Disabling Plan takes effect after a restart, and both `/plan` and `--permission-mode plan` are rejected while it is off.
## How It Works
In Plan mode:
- Qoder reads relevant files, searches the codebase, and analyzes the current state to understand what needs to be done and how.
- Its write access is restricted, focusing its output on a plan for your review.
- You can provide feedback on the plan and have Qoder adjust it until it meets your expectations.
This "look before you leap" approach reduces rework on complex tasks by ensuring the direction is correct before Qoder executes the changes.
## Executing with Goal
Plan is often used in conjunction with Goal: first, confirm the approach in Plan mode, then exit Plan and use `/goal set` to enter Goal mode, allowing Qoder to autonomously execute the approved plan to completion. This ensures the correct direction while letting Qoder handle the subsequent implementation.
For detailed information on Goal, see [Continuously Achieving Goals (Goal)](/cli/goal). If Plan is active before Goal execution, Qoder will restore the Plan state along with the goal when resuming across processes.
## When to Use
- **High-impact changes**: Modifications spanning multiple files or involving public interfaces and core logic.
- **Uncertain direction**: Scenarios with multiple implementation options that require comparison before deciding.
- **Desire for prior review**: When you want to see Qoder's intended approach before any changes are made.
For simple, well-defined minor changes, it is usually faster to let Qoder work directly in interactive mode without entering Plan.
## Related
- For the relationship between Plan and permission modes, see [Permissions](/cli/permissions).
- For how to choose between different working methods, see [Choosing the Right Working Approach](/cli/working-modes).
# Generate Repository Wiki
> Use qoder wiki to analyze a code repository and generate structured Wiki documentation.
## Generate Repository Wiki
RepoWiki analyzes a code repository and generates structured Wiki documentation through the `qoder wiki` command.
## Prerequisites
- Complete sign-in and authentication. You can sign in through `qoder` or set `QODER_PERSONAL_ACCESS_TOKEN`. For details, see [Sign-in and Authentication](/cli/authentication).
- Ensure that your machine can access Qoder services. The first run prepares the required Wiki component, and Wiki generation requires network access.
## Quick Start
Run the following command in the root directory of the target repository:
```bash
qoder wiki
```
On the first run, Qoder CLI automatically prepares the required component before starting Wiki generation. On subsequent runs, it checks the officially supported version and updates the component when necessary. No separate installation or update command is required.
## Common Options
```bash
# Generate a Wiki for a specific repository
qoder wiki --repo /path/to/repo
# Generate English and Chinese documentation
qoder wiki --language en,zh
# Generate a Wiki for a specific branch
qoder wiki --branch develop
# Discard reusable Wiki data and regenerate from scratch
qoder wiki --regenerate
```
| Option | Description |
| ------------------------ | -------------------------------------------------------------------------------------------- |
| `--repo ` | Target repository path. Specify this option multiple times to process multiple repositories. |
| `--language ` | Comma-separated output languages, such as `en,zh`. |
| `--branch ` | Git branch to process. If omitted, the current `HEAD` branch is used. |
| `--regenerate` | Regenerate from scratch. Existing reusable Wiki data is deleted. |
| `--help` | Display the options supported by the installed Wiki component. |
Options after `wiki` are passed to the Wiki component. Run `qoder wiki --help` to view the options supported by the current version.
## Specify the Working Directory
By default, RepoWiki uses the current working directory. To select another workspace at the Qoder CLI level, place `--cwd` or `--workspace` before `wiki`:
```bash
qoder --cwd /path/to/repo wiki
qoder --workspace /path/to/repo wiki
```
You can also place `--repo` after `wiki` to select one or more target repositories.
## Network and Proxy
Qoder CLI forwards common proxy and certificate environment variables when running RepoWiki, including `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY`, `NO_PROXY`, and `NODE_EXTRA_CA_CERTS`.
If component preparation, automatic update, authentication, or Wiki generation fails in a restricted network environment, verify the proxy and certificate configuration. For details, see [Network, Proxy, and VPC Issues](/cli/troubleshoot-network).
## FAQ
**Why is `qoder wiki` unavailable?**
Update Qoder CLI to the latest version, verify network access, and run `qoder --help` again.
**Why did authentication fail?**
Ensure that you are signed in or that `QODER_PERSONAL_ACCESS_TOKEN` is set correctly. For details, see [Sign-in and Authentication Issues](/cli/troubleshoot-auth).
**Why did component preparation or automatic update fail?**
Check your network, proxy, and certificate settings, then run `qoder wiki` again. If a usable version is already installed, Qoder CLI can continue using it when the version check is temporarily unavailable.
**How do I update the Wiki component?**
Run `qoder wiki`. Qoder CLI checks and applies the officially supported version automatically.
**How do I rebuild an existing Wiki from scratch?**
Run `qoder wiki --regenerate`. This removes existing reusable Wiki data before generation.
## Next Steps
- Sign-in and tokens: [Sign-in and Authentication](/cli/authentication).
- Network and proxy configuration: [Network, Proxy, and VPC](/cli/network).
- Command-line startup arguments: [CLI Commands and Parameters](/cli/cli-reference).
# Continuously Achieve Goals
## Overview
Goal is an autonomous execution mode in Qoder CLI. It is best suited for scenarios where you have a clear completion condition and want Qoder to work continuously until it is achieved. Once a goal is set, Qoder breaks it down into steps and executes them continuously, minimizing interruptions until the goal is completed or you manually stop it.
Goal is ideal for tasks with clear endpoints, such as "fixing all failing tests," "completing a refactoring until the build passes," or "implementing a feature according to requirements and passing self-tests."
## Setting a Goal
In an interactive session, use `/goal set` to create a goal:
```shell
/goal set
```
For example:
```shell
/goal set Fix all failing unit tests until all npm tests pass
```
After setting a goal:
- Qoder will start working continuously towards the goal, breaking it down into multiple steps if necessary.
- The permission mode will **automatically switch to `auto`** and lock the Shift+Tab toggle to minimize confirmation interruptions during execution. The previous permission mode is recorded and automatically restored when you clear or pause the goal.
- The interface will display a goal status indicator.
### Limiting Maximum Turns
Use the `--turns` parameter to limit the maximum number of conversation turns for goal execution. Once the limit is reached, Qoder will stop and wait for your instructions:
```shell
/goal set Refactor the payment module and ensure tests pass --turns 30
```
The value of `--turns` must be a positive integer; otherwise, the parameter will be ignored.
## Checking Goal Status
Use `/goal status` to check the progress of the current goal:
```shell
/goal status
```
It displays:
- **Goal**: The goal description.
- **Status**: Active, Paused, or TurnLimited.
- **Turns**: The number of turns used. If a limit is set, it is displayed as "used / limit".
- **Time**: The time consumed by the goal.
A goal is automatically cleared upon completion. Running `/goal status` afterward will prompt that there is no active goal.
If the goal is held by another session, the status will indicate this, and you can use `/goal take` to take over.
## Pausing and Resuming
When you need to temporarily interrupt the goal to handle something else, use `/goal pause` to pause:
```shell
/goal pause
```
When paused, Qoder reverts to the permission mode used before the goal was set. Use `/goal resume` to continue later:
```shell
/goal resume
```
Upon resuming, Qoder re-enters the autonomous execution state and continues working towards the goal. If the goal was in the Plan state before pausing, it will also be restored to that state.
## Taking Over a Goal
Goals can be persisted across sessions. If a goal was created and is held by another session, the current session cannot directly update it by default. Use `/goal take` to claim ownership of the goal for the current session:
```shell
/goal take
```
After taking over, the current session becomes the holder of the goal and can continue to advance and update it.
## Clearing a Goal
When a goal is completed or you no longer need it, use `/goal clear` to clear it:
```shell
/goal clear
```
When clearing a goal, Qoder reverts to the permission mode used before the goal was set.
> When Qoder determines that the goal has been achieved, it will also automatically mark the goal as completed and clear it, without requiring manual intervention.
## Working with Plan
Goal can be used in conjunction with Plan: use Plan first to analyze the problem and confirm the approach, then enter Goal to let Qoder execute autonomously until completion. If Plan is active before entering Goal, Qoder will re-enter the Plan state when resuming the goal, maintaining a consistent workflow.
For detailed information on Plan, see [Plan Before Execution (Plan)](/cli/plan-mode).
## Command Summary
| Command | Description |
| :-------------------------------------- | :--------------------------------------------------------------- |
| `/goal set [--turns ]` | Create or update a goal, with an optional limit on maximum turns |
| `/goal status` | View the current goal status |
| `/goal pause` | Pause the current goal |
| `/goal resume` | Resume a paused goal |
| `/goal take` | Take over goal ownership for the current session |
| `/goal clear` | Clear the current goal |
For complete command parameter descriptions, see [Goal Command Reference](/cli/goal-reference).
# Scheduled Execution Task
## Overview
Scheduled tasks allow Qoder CLI to automatically run a prompt or slash command at a specified time. You can schedule a task to run once at a future point in time, or repeatedly on a calendar schedule. This is ideal for scheduled inspections, periodic reports, and planned automation scenarios.
There are two types of scheduled tasks:
- **One-shot task**: Triggered once at the next matching time, then automatically deleted.
- **Periodic Task**: Triggered repeatedly according to a Cron schedule until deleted or automatically expired.
## Creating Scheduled Tasks
In an interactive session, describe the time and the action in natural language, and Qoder will create the scheduled task for you. For example:
```text
Check and summarize CI status every day at 9 AM
Generate a summary of last week's commits every Monday at 10 AM
Remind me to publish the release on February 28 at 2:30 PM
```
Qoder parses your description into a Cron Expression and creates the task. Tasks use the **standard 5-field Cron Expression** (minute, hour, day of month, month, day of week), interpreted based on the **local time zone** where the CLI is running.
If you want to repeat at a fixed time interval (e.g., "every 5 minutes"), use the simpler `/loop`. See [Loop Tasks](/cli/loop).
## Cron Expression
Scheduled tasks use a 5-field Cron Expression:
```text
┌───────── minute (0-59)
│ ┌─────── hour (0-23)
│ │ ┌───── day (1-31)
│ │ │ ┌─── month (1-12)
│ │ │ │ ┌─ day of week (0-6, 0=Sunday)
│ │ │ │ │
* * * * *
```
Supported field syntax: wildcard `*`, Single Value `N`, Step `*/N`, Range `N-M`, List `N,M,...`. In the day-of-week field, `7` is treated as Sunday (equivalent to `0`).
`L`, `W`, `?`, and Name Alias (such as `MON`) are not supported, nor is there a seconds field.
Examples:
| Cron | Meaning |
| :------------- | :------------------------------------------------ |
| `*/5 * * * *` | Every 5 minutes |
| `0 * * * *` | Every hour on the hour |
| `0 9 * * *` | Every day at 9:00 AM |
| `30 14 28 2 *` | February 28 at 2:30 PM (once in the current year) |
| `0 10 * * 1` | Every Monday at 10:00 AM |
| `0 9 * * 1-5` | Weekdays at 9:00 AM |
> All times are interpreted in the local time zone where the CLI is running. For example, `0 9 * * *` means 9:00 AM every day in the CLI's time zone.
## Storage and Persistence
The persistence behavior of scheduled tasks falls into two categories:
- **persistent task**: Written to `/.qoder/scheduled_tasks.json` in the project root directory, and persists across process restarts.
- **in-session task**: Stored only in memory, and disappears when the current session ends.
Tasks saved to disk are stored as a list of tasks in the file, with each task containing fields such as id, Cron Expression, prompt, and creation time.
## Execution Limits
Scheduled tasks have the following limits:
- **Maximum number of tasks**: Up to **50** tasks. Once the limit is reached, you must delete existing tasks before creating new ones.
- **Periodic Task auto-expiration**: Periodic tasks automatically expire **7 days** after creation, unless deleted earlier. Tasks that need to run long-term must be recreated.
- **Minimum granularity**: Since there is no seconds field, the minimum scheduling granularity is **1 minute**.
- **Single-process driven**: A file lock ensures that only one process drives the scheduling for the same project directory, preventing duplicate triggers.
To prevent a large number of tasks from triggering simultaneously, the scheduler adds a small amount of jitter to the trigger times: Periodic tasks are delayed by a fraction of the next cycle length (up to 15 minutes); one-shot tasks are triggered up to about 90 seconds early when aligned to 30-minute boundaries (top and half of the hour).
## Viewing and Deleting
During a session, you can ask Qoder to list current scheduled tasks or delete a specific task by its id. For example:
```text
List all scheduled tasks
Delete scheduled task
```
When creating a task, Qoder returns the task's id. Use this id to specify the task to cancel when deleting.
## Missed Tasks
If the CLI is not running at the time a task was supposed to trigger (e.g., the process was not started), the task is identified as "missed". Upon startup, Qoder will notify you of missed tasks so you can decide whether to run them manually or adjust the schedule.
For complete fields, limit values, and storage formats, see [Scheduled Task Reference](/cli/scheduled-reference).
# Loop Tasks
## Overview
`/loop` lets Qoder CLI run the same prompt or slash command over and over. It is ideal for scenarios such as polling status, continuous checking, and periodic repetitive actions, for example, "check deployments every 5 minutes" or "watch the CI pipeline until it turns green".
There are two pacing modes, selected by whether you give an interval:
| Mode | How to trigger it | Timing |
| :----------------- | :------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Fixed-interval** | Provide an interval (`/loop 5m …`) | Qoder converts the interval into a periodic schedule and creates a scheduled task. |
| **Dynamic-pacing** | Omit the interval (`/loop monitor CI`) | Qoder runs the task, then decides for itself when the next run is worth doing (60s–3600s). The loop ends as soon as it stops scheduling the next wake-up. |
If you need a precise calendar schedule (e.g., "every Monday at 9 AM"), use scheduled tasks instead. See [Scheduled Execution Task](/cli/scheduled-tasks).
## Command Format
```text
/loop [interval] [flags]
```
- `interval`: Optional time interval. If provided, the loop runs at a fixed interval; if omitted, Qoder paces itself.
- `flags`: Optional. Persistence (`--durable`, `--permanent`) and budget ceilings (`--max-turns`, `--max-credits`). Flags may appear anywhere in the input and are removed from the prompt before it is scheduled.
- `prompt`: The prompt or slash command to run repeatedly. If you omit it and a `.qoder/loop.md` file exists, Qoder loops over that task list instead.
Example:
```shell
/loop 5m /babysit-prs
/loop 30m check the deploy
/loop 1h /standup 1
/loop check the deploy every 20m
/loop monitor CI pipeline # No interval, Qoder picks the timing
/loop 10m --max-turns 6 check the deploy # Stops after 6 runs
```
Once created, Qoder will **execute the prompt immediately** rather than waiting for the first interval to begin.
## Interval Syntax
An interval consists of a number followed by a unit. Four units are supported:
| Unit | Meaning | Example |
| :--- | :------ | :------ |
| `s` | Seconds | `30s` |
| `m` | Minutes | `5m` |
| `h` | Hours | `2h` |
| `d` | Days | `1d` |
**The minimum granularity is 1 minute.** Since the underlying scheduler does not support second-level fields, seconds are rounded up to the nearest whole minute. For example, `30s` is treated as `1m`, and Qoder will inform you of the actual rounded interval.
Interval to Cron conversion rules:
| Interval | Corresponding Schedule | Description |
| :------------ | :--------------------------------- | :-------------------------- |
| `Nm` (N ≤ 59) | Every N minutes | |
| `Nm` (N ≥ 60) | Rounded to hours | Must evenly divide 24 hours |
| `Nh` (N ≤ 23) | Every N hours | |
| `Nd` | Midnight every N days (local time) | |
| `Ns` | Rounded up to minutes | Minimum 1 minute |
> If the interval does not evenly divide its unit (e.g., `7m` would result in uneven intervals from `:56` to `:00`, and `90m` cannot be expressed in whole hours), Qoder will select the nearest clean interval and inform you of the rounded value before creation.
## Two Formats
The interval can be placed at the beginning or expressed using an `every` clause at the end:
- **Interval at the beginning**: `/loop 5m check the deploy` → interval `5m`, prompt `check the deploy`.
- **every clause at the end**: `/loop check the deploy every 20m` → interval `20m`, prompt `check the deploy`. Natural expressions like `every 5 minutes` and `every 2 hours` are also supported.
Note that `every` is treated as an interval only when followed by a time expression. For example, in `/loop check every PR`, `every` is not a time expression and will be treated as part of the prompt, so the loop runs in dynamic-pacing mode.
## Budget Ceilings
A loop keeps running until it expires or you stop it, which makes it easy to spend more than you intended. Two flags put a ceiling on it:
```shell
/loop 10m --max-turns 6 check the deploy # At most 6 runs
/loop --max-credits 20 monitor CI # At most 20 credits
/loop 1h --max-turns=24 --max-credits=50 /standup 1
```
| Flag | Meaning |
| :---------------- | :------------------------------------------------------------------------------------------------------------------------- |
| `--max-turns N` | Stop after N runs. `N` is a whole number. |
| `--max-credits N` | Stop once N credits have been spent in total. Decimals are allowed, because a single run often costs less than one credit. |
Both flags also accept the `=` form (`--max-turns=6`). Only positive numbers are accepted—a ceiling of zero would retire the loop before its first run.
How the ceilings behave:
- **Set both, and whichever is reached first stops the loop.**
- **Runs are counted over the whole life of the task, not per session.** Restarting Qoder CLI does not reset the count, so a restart cannot be used to get past the ceiling.
- **The run count is checked before each run**, so `--max-turns 2` fires exactly twice, never a third time.
- **Credits are metered after a run finishes**, so the final run can end slightly above the ceiling (for example `3.2` against a ceiling of `3`). Qoder does not cut a run off midway, because the work you already paid for would be discarded.
- **Reaching a ceiling stops the loop for good.** The task is removed and you see a message such as `Scheduled task a1b2c3d4 stopped: it used 2 of 2 turns.` Qoder receives the same notice, so it reports the stop instead of continuing to reason as though the loop were still running. To keep going, start a new loop with a fresh ceiling.
- **In dynamic-pacing mode the ceiling sticks to the loop.** You only pass it once, on the `/loop` that starts the loop; it stays in effect for every later wake-up. Stopping the loop clears both the ceiling and the usage, so the next `/loop` starts from zero.
## Viewing and Changing Usage
`/crontab` opens the scheduled task panel, where the `USAGE` column shows what each loop has consumed:
```text
USAGE
3/10 turns · 12.5/50 credits Both ceilings set
2 turns · 8.25 credits No ceiling
1/5 turns · —/50 credits Spend not metered yet
```
On the detail page of a task you can change the ceilings without recreating the loop: press `t` for the run ceiling and `b` for the credit ceiling. Entering an empty value removes that ceiling.
## Persistence, Automatic Expiration, and Cancellation
By default a `/loop` task lives in the current session only: it fires on schedule while Qoder CLI is running and disappears when the process exits. Recurring tasks also expire automatically **7 days** after creation.
Two flags change that:
| Flag | Effect |
| :-------------- | :-------------------------------------------------------------------------- |
| `--durable` | Persist the task to disk so it survives restarts, with no automatic expiry. |
| `--durable 30d` | Persist the task and expire it 30 days from now. |
Both flags apply to fixed-interval loops. A dynamic-pacing loop always lives in the current session.
Upon successful creation, Qoder will display the scheduled content, the corresponding cycle, whether the task is persisted, the automatic expiration time, and the task ID for cancellation. To stop it early, ask Qoder to cancel the corresponding loop task using this ID, delete it from the `/crontab` panel, or—in dynamic-pacing mode—simply ask Qoder to stop the loop.
For complete parameters, default values, and expiration rules, see the [Loop Command Reference](/cli/loop-reference).
# Run in Scripts
## Overview
Headless (non-interactive) mode allows Qoder CLI to run without an interactive interface—it receives a prompt, executes the task, outputs the result to standard output, and exits. It is ideal for embedding Qoder into Shell scripts, automation workflows, and CI/CD Pipelines.
To enter Headless mode, add the `--print` flag (short form `-p`):
```shell
qoder -p "Explain the architecture of this code repository"
```
Since there is no one around to confirm, permissions in Headless mode must be pre-configured—any operation that would normally require a pop-up confirmation will be automatically denied in plain text Headless mode. See [Permissions](/cli/permissions) for details.
## Basic Usage
Pass the prompt as an argument and add `-p`:
```shell
qoder -p "Generate a commit message for this change"
```
You can also pass the prompt via standard input:
```shell
echo "Summarize all code changes from yesterday" | qoder -p
```
Capture the output in a script:
```shell
result=$(qoder -p "List all exported functions in the src directory")
echo "$result"
```
## Output Format
Use `--output-format` (short form `-o`) to specify the output format. The default is `text`:
| Format | Description | Use Case |
| :------------ | :---------------------------------------------------- | :---------------------------------------------- |
| `text` | Plain text result (default) | Direct reading, simple scripts |
| `json` | Single JSON Object containing the result and Metadata | Programmatic parsing of the final result |
| `stream-json` | Line-by-line JSON Message Stream | Real-time consumption of intermediate processes |
Example:
```shell
# Plain text (default)
qoder -p "Explain the purpose of main.ts"
# JSON: for easy script parsing
qoder -p "Explain the purpose of main.ts" --output-format json
# Stream JSON: consume message streams in real time
qoder -p "Refactor the utils module" --output-format stream-json
```
The Input Format can be specified using `--input-format`, supporting `text` and `stream-json`. When using `stream-json` input, you can continuously send Structured Messages via standard input.
## Common Flags
Headless mode is often used in combination with the following flags:
| Flag | Description |
| :----------------------------- | :------------------------------------------------------ |
| `-p, --print` | Print the response and exit (non-interactive) |
| `-o, --output-format ` | Output Format: text / json / stream-json |
| `--input-format ` | Input Format: text / stream-json |
| `--max-turns ` | Limit the maximum Conversation Turns for a single query |
| `--permission-mode ` | Set the permission mode |
| `--allowed-tools ` | Allow only specified tools |
| `--disallowed-tools ` | Deny specified tools |
| `-m, --model ` | Specify the Model |
| `--session-id ` | Use the specified session ID |
| `-w, --cwd ` | Switch the working directory before startup |
For a complete list of flags, see [CLI Commands and Parameters](/cli/cli-reference).
## Permission Control
Since there is no interactive confirmation in Headless mode, you need to pre-determine which operations can be executed automatically using permission flags:
```shell
# File edits are auto-approved, shell commands are still rejected
qoder -p "Refactor utils module" --permission-mode accept_edits
# Allow only specific tools
qoder -p "Check status" --allowed-tools 'Read,Bash(git status)'
# Allow all (for trusted scenarios only)
qoder -p "Run database migration" --yolo
```
- In plain text Headless mode, any operation that "requires confirmation" defaults to deny. If driven by a Host Program via the stream-json protocol (e.g., Agent SDK), confirmation requests are forwarded to the Host Program for decision. See "Consumption methods of `ask` in different runtime environments" in [Permissions](/cli/permissions).
- Use `--permission-mode accept_edits` to automatically approve safe file edits within the working directory.
- Use `--yolo` (equivalent to `--permission-mode bypass_permissions`) to skip all confirmations. **This is only recommended for use in fully trusted environments**.
For details on the behavior of each permission mode, see [Permissions](/cli/permissions).
## CI/CD Example
In a pipeline, authentication is typically completed first via Environment Variables before running in Headless mode:
```shell
export QODER_PERSONAL_ACCESS_TOKEN="your_token"
qoder -p "Review these changes and list potential issues" \
--output-format json \
--permission-mode accept_edits \
--max-turns 20
```
See [Sign-in and Authentication](/cli/authentication) for authentication methods. Set the output format to `json` to make it easier for subsequent pipeline steps to parse Qoder's results.
# Process Tasks in Parallel
## Overview
When you want to work on multiple tasks in the same repository simultaneously without them interfering with each other, you can use parallel collaboration. Qoder CLI provides several isolation methods: using **Worktree** to place different tasks into independent Git checkouts, using **Background Agents / Tasks** to run multiple subtasks in parallel, and using **Subagents** to delegate complex work to specialized subagents.
This way, each task has its own workspace and context, preventing multiple sessions from sharing the same directory and overwriting each other's changes.
## Worktree Isolation
Worktree allows each task to run in an independent Git working tree without affecting others. Start it with `--worktree`:
```shell
qoder --worktree feature-a
qoder --worktree feature-a "Implement login fix"
qoder --worktree
```
- When no name is provided, Qoder automatically generates a worktree name.
- New named worktrees are placed under `/.qoder/worktrees/`, and a corresponding temporary branch is created.
- If a worktree with the same name already exists, it is reused directly instead of being recreated.
This must be run within a Git repository and requires Git to be installed locally. For complete instructions on creating, copying files to, restoring, and cleaning up worktrees, see [Run Tasks](/cli/run-tasks).
## Parallel Sessions
Using Worktree, you can start separate sessions for different tasks, allowing them to run in parallel within their own isolated directories:
```shell
# Terminal 1: Work on Task A in the feature-a worktree
qoder --worktree feature-a "Implement login fix"
# Terminal 2: Work on Task B in the feature-b worktree
qoder --worktree feature-b "Refactor logging module"
```
Each session has its own working tree and branch, keeping changes isolated from one another. Once completed, they can be committed or merged separately.
## Background Agents and Subagents
For a single complex task, you can break it down and delegate parts to multiple Subagents for parallel processing. Use `/tasks` to view currently running background tasks:
```shell
/tasks
```
Subagents also support worktree isolation: when a Markdown Subagent needs to modify files in an isolated checkout, add `isolation: worktree` to its definition. Clean Subagent worktrees are automatically deleted upon completion, while those with changes are retained.
For creating, configuring, and orchestrating Subagents, see [Subagent](/cli/builtins-reference).
## Restoration and Cleanup
When a session ends, Qoder prints the worktree path and the command to resume the session. When exiting interactively, it checks for uncommitted files and new commits in the worktree: clean worktrees can be automatically deleted, while those with local files or commits will prompt you to choose whether to keep or delete them.
To clean up manually:
```shell
git worktree remove
git branch -d worktree-
```
## Tips
- **One task per worktree**: Place unrelated tasks in their own worktrees to avoid overlapping changes.
- **When local files are needed**: A new worktree is a clean checkout and does not include untracked files by default. To copy files like `.env`, declare them using `.worktreeinclude` at the repository root. For details, see [Run Tasks](/cli/run-tasks).
- **Clean up promptly**: Delete unnecessary worktrees and temporary branches after tasks are completed and merged to keep the repository tidy.
# Agent Teams
Agent Teams turns one interactive Qoder CLI session into a small group of collaborating agents. The entry point stays the same: describe the goal in the current session, and the main Agent can create teammates to research, implement, review, and hand work to each other.
Use Agent Teams when a task is large enough to benefit from multiple focused members working in parallel, such as exploring several modules, separating implementation from review, or moving a refactor through research, coding, and validation.
> **Beta**
>
> Agent Teams is currently a beta feature and is not enabled by default. Set the feature flag before starting Qoder CLI: `QODER_AGENT_TEAMS=1 qoder`.
>
> The flag can also be stored as `QODER_AGENT_TEAMS=1` in the user-level configuration `.env` file so later sessions enable Agent Teams automatically. Default user-level configuration path: `$HOME/.qoder/.env` on macOS/Linux, and `%USERPROFILE%\.qoder\.env` on Windows. Restart Qoder CLI after changing `.env`.
## What Agent Teams are
An Agent Team has two kinds of participants:
| Role | Description |
| :--------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Main Agent | The Agent that talks directly with the user. It understands the goal, splits work, summarizes results, and reports important progress. |
| Teammate | A member created by the main Agent, such as `researcher`, `coder`, or `reviewer`. A teammate has its own context and can receive follow-up SendMessage and Tasks. |
```text
Qoder CLI session
+-- main conversation
| `-- The main Agent talks with the user, delegates work, and summarizes results
|
+-- Agent Team
| +-- @researcher explores code paths
| +-- @coder implements changes
| `-- @reviewer checks risks
|
`-- shared Task list
+-- Task A owner=@researcher
+-- Task B owner=@coder
`-- Task C owner=@reviewer
```
No manual team creation is required. An interactive session has one current team. When the main Agent needs a teammate, it creates a named Agent and adds that member to the team.
## How to use Agent Teams
The most reliable request style is to mention Agent Teams explicitly and describe the teammate roles:
```text
Use Agent Teams for this refactor.
Create three teammates: researcher, coder, and reviewer.
1. researcher traces the auth module call flow.
2. coder changes the code based on researcher's findings.
3. reviewer checks risks and missing tests.
Return a change summary, changed files, and verification results.
```
If the request only says “parallelize” or “have a few agents look at this,” Qoder CLI may choose ordinary Subagents, background tasks, or a workflow. Ask for Agent Teams directly when teammates should keep collaborating in the same session.
## How it works
Agent Teams are built around teammates, SendMessage, and a shared Task list.
### Collaboration flow
Agent Teams can be understood as a collaboration loop organized by the main Agent. The main Agent understands the goal, creates teammates, assigns Tasks, uses SendMessage to coordinate questions and findings, and summarizes results. Teammates do the focused work, while the shared Task list records ownership and progress.
```text
User goal
|
v
+------------+
| main Agent |
+------------+
| Create teammates
| Assign / update shared Tasks
| Collect and summarize results
|
+-----------------------+
| |
v v
+------------------+ +------------------------+
| shared Task list | | SendMessage |
| owner / status | | asks / finds / results |
+------------------+ +------------------------+
| |
+-----------+-----------+
|
v
+-------------+ SendMessage +----------+
| @researcher | <---------> | @reviewer |
+-------------+ +----------+
| |
+-----------+-------------+
|
v
progress and results
|
v
main Agent
|
v
final response
```
### Lifecycle and resume
An Agent Team exists only inside the currently open TUI session. Each time an interactive session starts with Agent Teams enabled, Qoder CLI prepares a temporary team for that session. The main Agent creates teammates inside that team.
Within the same TUI, a teammate can move through `running -> idle -> running` multiple times. `idle` means the teammate has no active work; it does not mean the teammate has exited.
```text
Current TUI session
+-- main conversation
+-- Agent Team
| +-- @researcher running / idle
| `-- @reviewer running / idle
`-- shared Task list
```
When the TUI exits, Qoder CLI stops the teammates from that session and clears that team state. Later, `resume` restores the main conversation history, but it does not bring back the teammates created in the previous TUI or their last running or idle state. Summaries or SendMessage content already visible in the main conversation remain as history, but the previous teammates are no longer running.
If team collaboration is still needed after `resume`, the main Agent should create new teammates. Teammates only live inside the current TUI session and do not carry over to the next `resume` after the TUI exits.
### TUI display
Agent Teams are currently displayed inside one TUI window. The bottom of the conversation shows an agents list. The down arrow opens the list, the up and down arrows select the main conversation or a teammate, Enter switches to the selected view, and Esc returns to the main conversation.
Multiple split TUI panes are not currently supported. Teammates are not shown side by side; their conversation views are opened by switching inside the same window.
### Teammates
When the main Agent creates a teammate, it gives that member a stable name such as `researcher`. The team can use that name later for SendMessage, Task assignment, and status tracking.
After a teammate finishes its current work, it usually becomes idle. Idle does not mean exited; it means the teammate has no active work and can be woken by a new SendMessage or Task.
```text
@researcher running -> idle -> running -> idle
^ |
| `-- Woken by a new task
`-- Current turn finished
```
### SendMessage
The main Agent and teammates can use SendMessage to communicate with each other. A teammate's normal text output is not automatically sent through SendMessage; information meant for a specific team member is sent through SendMessage.
In the UI, SendMessage content usually appears as “Message from @researcher,” making questions, findings, and results easier to follow during collaboration.
### Shared Tasks
Agent Teams can use the shared Task list. The main Agent can create tasks first, then teammates can handle the matching pieces of work.
```text
shared Task list
+-- [in progress] Map old API call sites owner=@researcher
+-- [pending] Implement the new adapter owner=@coder
`-- [pending] Add migration tests owner=@tester
```
The shared Task list makes collaboration easier to follow: it records who owns each task, what is complete, and what depends on other work. Completing a Task does not shut down the teammate; the teammate can remain available for more work.
## Agent Teams vs. Subagents
Agent Teams use Agent capabilities, but they are different from ordinary Subagent delegation.
| Area | Subagent | Agent Teams |
| :------------ | :-------------------------------------- | :------------------------------------------------------------------ |
| Best for | One focused subtask | Complex work with several collaborating members |
| Lifecycle | Usually returns one result and ends | Teammates can become idle and receive more work in the same session |
| Communication | Results mainly return to the main Agent | Main Agent and teammates can communicate through SendMessage |
| Coordination | Mostly orchestrated by the main Agent | Can use a shared Task list for assignment and tracking |
| Identity | Based on Subagent type | Based on runtime names such as `@coder` or `@reviewer` |
In short:
- Use a Subagent for handing off one clear subtask and getting a result back.
- Use Agent Teams for multiple teammates that should keep collaborating, communicate through SendMessage, claim Tasks, and move through phases together.
## When to use Agent Teams
Good fits:
| Scenario | Why it fits |
| :------------------------- | :------------------------------------------------------------------------------------------ |
| Large code exploration | Different teammates can inspect different areas and report findings to the main Agent. |
| Implementation plus review | One member can write code while another independently reviews risks, tests, and edge cases. |
| Parallel work streams | Independent subtasks can move at the same time. |
| Repeated handoffs | Teammates keep their names and context for follow-up work. |
| Visible coordination | Shared Tasks show owners, status, and dependencies. |
Poor fits:
| Scenario | Better option |
| :------------------------------------- | :------------------------------------------------------- |
| Reading one file or finding one symbol | Ask the main Agent to read or search directly. |
| One independent subtask | Use an ordinary Subagent. |
| A fixed reusable multi-stage process | Use a workflow. |
| A small low-cost task | Use fewer agents to avoid extra context and token usage. |
## Tips
- Give every teammate a short name and clear role, such as `researcher`, `coder`, or `reviewer`.
- State the expected output, such as root cause, change summary, verification results, risks, or follow-up suggestions.
- Use shared Tasks when the work has more than a few steps, so ownership, status, and dependencies are easy to follow.
- Keep the team small at first. Two to four teammates is enough for most tasks.
- Treat idle as available, not finished. Ask the main Agent to shut down teammates when collaboration is no longer needed.
## Examples
### Parallel exploration
```text
Use Agent Teams to analyze this login issue.
Create two teammates:
1. researcher checks auth and session code.
2. tester checks existing tests and reproduction paths.
Return the likely root cause, impact scope, risks, and a recommended fix.
```
### Implementation with independent review
```text
Use Agent Teams for this fix.
Have coder make the code change, then have reviewer independently review the final diff.
reviewer should check edge cases, test coverage, and possible regressions.
Return what changed, how it was verified, and any remaining risk.
```
### Shared Task list
```text
Use Agent Teams and the shared Task list for this migration.
Create these Tasks:
1. Map old API call sites.
2. Implement the new API adapter.
3. Add migration tests.
Then create researcher, coder, and tester teammates to claim those tasks.
Include each Task's completion status, key changes, and verification results in the final result.
```
# Cross-Session Messaging
Cross-session messaging lets two Qoder CLI sessions running on the same machine, under the same user account, see each other and exchange messages. A session can ask a peer to pick up a task, hand it a file, or answer a question, without you copying text between terminals.
Use it when work naturally spans more than one session — one terminal on the backend and one on the frontend, or a long-running session you want to hand something to from a second window.
> **Beta**
>
> Cross-session messaging is a beta feature and is not enabled by default. Set the feature flag before starting Qoder CLI: `QODER_FEATURE_CROSS_SESSION=1 qoder`.
>
> The flag can also be stored as `QODER_FEATURE_CROSS_SESSION=1` in the user-level configuration `.env` file so later sessions enable it automatically. Default user-level configuration path: `$HOME/.qoder/.env`. Restart Qoder CLI after changing `.env`.
>
> The feature requires Unix domain sockets and is available on macOS and Linux only.
## How it works
When the feature is on, each session listens on a private socket and records it in a per-user registry. Other sessions read that registry to discover peers, and connect directly to deliver a message.
```text
Session A (terminal 1) Session B (terminal 2)
+-- listens on its own socket +-- listens on its own socket
+-- ListAgents --------------------> reads the registry, finds B
`-- SendMessage --------------------> delivered into B's next turn
```
Both the socket and its directory are readable only by your own user account. Sessions belonging to other users on the same machine cannot see or reach yours.
## Discovering peers
Ask the Agent to list what it can reach, or let it call `ListAgents` on its own. The listing has two groups: agents running inside the current session, and peer sessions elsewhere on the machine.
```text
Agents in this session (address by name):
- Reviewer
Peer sessions (other Qoder sessions on this machine):
- api-service — interactive, idle, started 12m ago, cwd /home/dev/api, handle -3f
- api-7c — interactive, busy, started 3m ago, cwd /home/dev/api
- web-2b — interactive, idle, started 40m ago, cwd /home/dev/web
```
A session's name is its current title, so it changes when you run `/rename` and when the Agent retitles the conversation. The status column tracks the session in the same way: `busy` while its Agent is working, `waiting` while it is asking for a confirmation, `shell` while its user is at a shell prompt, and `idle` otherwise.
A session that has no title is named after its working directory, plus its **handle** — the `-7c` above. Without it, every session working in the same directory would present the same name and none of them could be addressed. Two sessions in `/home/dev/api` therefore appear as `api-7c` and `api-3f`, not twice as `api`.
A peer is addressed by the label in its row, or by its handle alone. A handle is derived from the socket the session listens on, so it is the same in every session's listing, and it does not change when the session is retitled — `-7c` reaches that session whatever it is called by then. A titled session's name has no handle in it, so its row states one: `handle -3f`.
Run `/peers` to see the same list along with the handle this session is reachable at.
## Mentioning a peer in the prompt
Type `@` followed by at least one character to complete on peer sessions along with files and agents. Peer rows lead with the `@` and are described as `session`, with the session's status and how long it has been running, so they are distinguishable from a file of the same name.
```text
@rev
@reviewer session · idle · started 3m ago
```
Accepting the row inserts the label that addresses that session. A label containing spaces is inserted with the spaces escaped, the same way a file path is.
Mentioning a session tells the Agent which one you mean; it does not send anything. Ask for what you want in the same message — "ask @reviewer to rerun CI" — and the Agent messages it. A message that only mentions a session does not message it.
If the name matches more than one live session, the Agent is given the labels that each address exactly one, and asks which you meant rather than guessing. Names are self-chosen and unverified, so nothing addresses a session on a name alone when it is ambiguous.
Typing `@` on its own does not list peer sessions, and a mention that matches nothing is left in the text as written.
## Sending a message
The Agent uses the same `SendMessage` tool it uses for teammates, with a peer name as the recipient. Files can be attached by absolute path and are copied to the recipient so it can read them.
A send reports honestly. If the peer exited between the listing and the send, the result says so and suggests listing again rather than silently succeeding.
## Controlling what arrives
Each session decides for itself what to do with incoming peer messages, through the `security.crossSessionInbound` setting:
- `accept` — deliver the message into the session's next turn.
- `hold` — park the message for your review; the Agent never sees it until you approve it.
- `refuse` — decline everything; nothing is delivered and no attachment is written to disk.
When the setting is unset, the fallback depends on how this session handles permissions. A session that bypasses permission checks holds incoming peer messages for your approval, because anything a peer asked for would otherwise run without a further prompt. A session that still asks for confirmation accepts them, since a peer cannot use it to skip a check it would face itself.
In a session with nobody to review anything — a non-interactive run that was given an explicit socket path — a message this fallback would have held is refused instead, so the sender is told immediately rather than waiting for a review that cannot happen. If such a session is meant to take instructions from peers, set `security.crossSessionInbound` to `accept` explicitly; a value you configure yourself is always honoured, even there.
Project-level settings may only make this stricter. A value in a repository's checked-in settings can tighten `accept` to `hold`, but never loosen `hold` to `accept`. Because that means a repository can override your own choice, `/peers` always names the setting in effect and the file it came from.
## Approving a held message
When a message is held because the trust question cannot be settled automatically, the session asks you directly:
```text
Another session sent this one a message
From worker -7c (name and address are supplied by the sender and are not verified)
This session bypasses permission checks, and the sender did not declare its own.
Anything it asks for would run without a further prompt.
please run the integration suite and report the failures
❯ Deliver it to this session
Decline — drop it and tell the sender
```
The prompt is the last thing this session will put on screen, so it never interrupts a permission confirmation or a dialog you are part-way through. It only appears when nothing else is asking you for something. Approving delivers the message on the next turn; declining drops it and tells the sender it was refused. The excerpt is shortened for display — approving delivers the whole message — and any attached files are named by count, because they are copied on arrival and removed again if you decline.
Only one approval is asked at a time, and only while the screen is otherwise free. A message that arrives while a prompt or a dialog is open is still held and is reviewed with `/peers` instead, as is one whose prompt was already open when something else needed the screen — that message goes back to the queue rather than waiting out its deadline behind whatever replaced it.
How long the prompt waits is set by `general.dialogExpiry`, which defaults to five minutes. When it lapses the message is dropped and the sender is told it expired rather than that you refused it — a distinction the sending Agent can act on. `never` removes the deadline for other dialogs but not for this one, so a single unanswered prompt cannot stop every later message from asking.
A message held because you configured `hold` yourself is parked without a prompt, since your own standing instruction is not a question. Those are reviewed with `/peers`.
A `hold` that came from a settings file in the repository does prompt. It is the same value, but it is the repository's decision rather than yours, so it is put to you instead of quietly removing a prompt you would otherwise have seen.
## Reviewing held messages
Run `/peers` to see the policy in effect, reachable peers, and anything waiting for review:
```text
/peers
```
The first line always states the inbound policy in effect and where it came from — your own settings, a repository setting, or the permission-mode fallback, in which case it states the rule rather than a single example of it. This is worth reading when messages are not arriving at all, since a repository setting of `refuse` produces no held messages to explain itself.
Each held message shows an id, its sender, why it was held, and a preview. The sender is identified by the handle derived from the address it asked replies at, and `/peers` says whether a session is still reachable there. Neither that address nor the name beside it is verified — no session can prove who sent it a message — but a handle can be checked against the peer list above it, where a name can only be read.
Approve or decline by id:
```text
/peers approve ab12cd34
/peers deny ab12cd34
```
Approving queues the message for the next turn. Declining drops it and tells the sender it was refused.
## What a peer message can and cannot do
A message from a peer is treated as a request from a colleague, not as an instruction from you:
- It never counts as your approval for a pending permission prompt.
- A leading `/` in a peer message is plain text, never a slash command.
- Permission boundaries are per-session. If a peer was denied an action and asks another session to perform it instead, the receiving Agent is instructed to refuse and surface it to you.
## Security notes
Isolation rests on file permissions: the socket and its directory are restricted to your own user account. Within that boundary the sender's self-reported name is not cryptographically verified, so any process already running as you could present itself as any peer. Treat cross-session messages as trusted only to the extent that everything running under your user account is trusted, and prefer `hold` on sessions that run with elevated permissions.
## Settings reference
- `security.crossSessionInbound` — `accept`, `hold`, or `refuse`. Controls inbound peer messages for this session.
- `general.dialogExpiry` — `60s`, `5m`, `10m`, or `never`. How long an approval prompt waits before the message is dropped as expired. Defaults to `5m`. Read from your own settings only, never from a repository.
# Dynamic workflows
Dynamic workflows let Qoder CLI run a structured multi-agent process in the background. Use them when a task needs phased execution, broad fan-out, cross-checking, or a repeatable process that should be visible while it runs.
A workflow moves the orchestration plan into a JavaScript script. The script decides which subagents to start, how to group work into phases, how to combine intermediate results, and what final output should return to the session.
## **When to Use Workflows**
| Use | Best for |
| :------- | :---------------------------------------------------------------------------------------- |
| Subagent | One focused side task where only the summary needs to return to the main conversation. |
| Skill | Reusable instructions, domain knowledge, or a process that the main agent should follow. |
| Workflow | Repeatable orchestration across many subagents, phases, branches, or verification passes. |
Choose a workflow when the task is larger than a single agent call: repository audits, broad research, migration planning, release checks, cross-file sweeps, or review processes that need independent perspectives before a final answer.
## **What Workflows Do**
| Capability | Description |
| :------------------------- | :------------------------------------------------------------------------------- |
| Scripted orchestration | Keep the loop, branches, phases, and intermediate state in a workflow script. |
| Multi-agent fan-out | Start multiple subagents for independent slices of work. |
| Phased execution | Show progress through named stages such as scan, analyze, verify, and summarize. |
| Parallel or pipelined work | Run independent branches together, or move each item through staged processing. |
| Background execution | Continue using Qoder CLI while the workflow runs. |
| Reusable flows | Save named workflows for project, personal, plugin, or built-in use. |
## **Run a Workflow**
Ask Qoder CLI to use a workflow in natural language:
```text
Use a workflow to review this repository for security risks and summarize findings.
```
You can also ask for a saved or built-in workflow by name:
```text
Use the deep-research workflow to investigate the tradeoffs of this architecture decision.
```
Qoder CLI may create a workflow for the current request, or use a saved workflow if one matches the task. When a dynamic workflow is generated, Qoder CLI shows the planned workflow before it runs. You can run it, view the raw script, reject with feedback, or cancel.
Workflows run as background tasks. After launch, Qoder CLI returns a workflow run ID and keeps execution progress available in the task UI.
## **Deep Research**
`deep-research` is a built-in workflow for questions that need broad web research, source comparison, and claim-level verification. Invoke it directly with a focused research question:
```text
/deep-research Compare the security and operational tradeoffs of passkeys and passwords for a consumer web app in 2026.
```
If the request is too broad to research directly, Qoder CLI asks clarifying questions first and passes the refined question to the workflow.
The workflow runs five phases:
| Phase | What happens |
| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Scope** | Decomposes the question into complementary search angles selected for the topic. |
| **Search** | Runs one Web Search agent per angle in parallel. Each agent ranks results against the original question and excludes obvious low-quality or irrelevant pages. |
| **Fetch** | Deduplicates URLs, fetches relevant public pages, assesses source quality, and extracts concrete, falsifiable claims with supporting quotations. |
| **Verify** | Independent agents challenge the extracted claims. Claims that do not survive cross-checking are excluded, while claims that could not be checked are marked unverified instead of refuted. |
| **Synthesize** | Merges semantically equivalent claims, groups related findings, assigns confidence levels, and produces a cited report with an executive summary, caveats, and open questions. |
The final report includes evidence, confidence, and source URLs for its findings. Claims that fail verification do not appear as findings. If an agent or network request fails before a claim can be checked, the report lists it as unverified rather than treating it as refuted.
Deep Research uses the Web Search and Web Fetch tools through its child agents. Authenticated, private, paywalled, or unavailable pages may not yield usable content. Because the workflow launches multiple agents and can consume tokens quickly, start with a specific question and narrow the time range, region, audience, or decision criteria when they matter.
## **Monitor Workflows**
Use `/workflows` in the TUI to open the workflow task panel.
```text
/workflows
```
From the panel, you can inspect running and completed workflow tasks, view status, phases, agents, logs, output paths, errors, and final results. `/tasks` also shows workflow tasks together with other background tasks.
When a workflow is running, the detail view lets you inspect individual agents. If an agent is still controllable, you can skip or retry that agent from the workflow detail view.
## **Saved Workflows**
Saved workflows let you reuse a known process by name. Qoder CLI discovers workflows from these locations:
| Scope | Location | Use when |
| :------- | :------------------------ | :---------------------------------------------------------------- |
| Project | `.qoder/workflows` | The workflow belongs to the current repository or team. |
| User | `~/.qoder/workflows` | The workflow is personal and should be available across projects. |
| Plugin | Plugin-provided workflows | The workflow is shipped as part of a plugin. |
| Built-in | Qoder CLI built-ins | The workflow is provided by Qoder CLI. |
Project workflows take priority over plugin and built-in workflows when names overlap. Use project workflows for team-owned processes that should travel with the repository, and user workflows for personal processes that should not be committed.
A saved workflow is a JavaScript file that starts with an exported `meta` object. The metadata gives Qoder CLI a name, description, phases, and optional usage hints or input schema.
```js
export const meta = {
name: "repo-audit",
description: "Audit a repository area and summarize risks",
whenToUse: "Use when the user asks for a structured repository audit",
phases: [
{ title: "Scan", detail: "Find relevant files and areas" },
{ title: "Analyze", detail: "Run focused analysis agents" },
{ title: "Summarize", detail: "Merge findings into a final report" }
]
};
```
After saving it under `.qoder/workflows/repo-audit.js`, you can ask Qoder CLI:
```text
Run the repo-audit workflow for the authentication module.
```
Saved workflows can receive input through `args`. Use `args` for target paths, issue IDs, research questions, options, or any other value that should change per run without editing the workflow script.
## **How Workflows Run**
Workflow scripts are plain JavaScript. They can use workflow helpers such as `agent()`, `parallel()`, `pipeline()`, `phase()`, `log()`, `workflow()`, and `args`.
1. Qoder CLI selects a saved workflow or creates a dynamic workflow for the task.
2. If review is required, Qoder CLI shows the workflow name, phases, script, and run options.
3. The workflow launches as a background task.
4. The script starts child agents and groups them into phases.
5. Intermediate results stay inside the workflow runtime instead of filling the main conversation.
6. Final output is written to the workflow run output and summarized back into the session.
Workflow runs store scripts, manifests, journals, transcripts, and output under the session directory in `.qoder/sessions`.
## **Permissions and Safety**
Dynamic workflows can run multiple subagents and may consume tokens quickly. Start with a narrow target when validating a large or expensive workflow.
Workflow scripts do not get direct access to your shell, filesystem, network, Node.js APIs, or MCP servers. Side effects happen through child agents, and those agents still go through Qoder CLI tools, permissions, hooks, and sandbox settings.
Use [Permissions](/cli/permissions) to control what workflow child agents can do, and [Hooks](/cli/hooks) to enforce organization-specific policy before or after tool calls.
# Session Management
## Overview
Every time you run Qoder CLI, it creates a **session** that records the complete history of the conversation—your inputs, Qoder's responses, and tool calls. Sessions can be continued, resumed, named, branched, and cleared, allowing you to flexibly switch between different tasks and pick up where you left off after an interruption.
Sessions are isolated and stored per project. Each session has a unique session ID, and session logs are saved in project-organized directories under the User Configuration Directory (default `~/.qoder/projects//.jsonl`).
## New Session
Running `qoder` directly in the project root directory starts a new session, and the system automatically generates a session ID:
```shell
qoder
```
In an interactive session, use `/new` to start a brand new session; `/clear` clears the Conversation History and also starts a new session, both achieving similar results.
### Naming Sessions
Use `-n` (`--name`) to set an easily recognizable display name for a session:
```shell
qoder -n "Refactor login"
```
You can also use `/rename` to rename the current session from within the session.
### Specifying a Session ID
Use `--session-id` to specify a session ID, making it easy for scripts or automated workflows to reference a fixed session:
```shell
qoder --session-id 00000000-0000-0000-0000-000000000000
```
## Continue and Resume
### Continuing the Most Recent Session
Use `-c` (`--continue`) to directly continue the most recent session for the current project:
```shell
qoder -c
```
### Resuming a Specific Session
Use `-r` (`--resume`) to resume a previous session by its ID:
```shell
qoder -r
```
Running `qoder --resume` without an ID opens the Session Browser, allowing you to select the session to resume from a list. In an interactive session, the `/resume` command also opens the Session Browser; `/continue` continues the most recent session.
## Forking Sessions
Use `--fork-session` to fork a resumed session into a new branch instead of continuing the original session. This allows you to explore different directions from a historical point while keeping the original session intact:
```shell
qoder -r --fork-session
```
In an interactive session, you can also use `/branch` to create a branch from the current session.
## Exporting Sessions
Use `/export` to export the current conversation to a file or copy it to the clipboard for sharing, archiving, or further analysis elsewhere:
```shell
/export
```
## Listing and Deleting
Use `--list-sessions` to list currently available sessions:
```shell
qoder --list-sessions
```
Use `--delete-session` to delete a session by its list index:
```shell
qoder --delete-session
```
## Session Storage Location
Session logs are isolated by project and saved under the User Configuration Directory:
```text
~/.qoder/projects//.jsonl
~/.qoder/projects///state.json
```
Within this directory, `.jsonl` stores the conversation logs, and `state.json` stores the session state. The User Configuration Directory defaults to `~/.qoder` and can be customized via the `QODER_CONFIG_DIR` Environment Variable.
## Commands and Arguments Quick Reference
| Command / Argument | Description |
| :------------------------- | :------------------------------------------------------------------------ |
| `qoder` | Create a new session |
| `-c, --continue` | Continue the most recent session |
| `-r, --resume [id]` | Resume a specific session; opens the Session Browser if no ID is provided |
| `-n, --name ` | Set the session display name |
| `--session-id ` | Use a specified session ID |
| `--fork-session` | Create a branch from a resumed session |
| `--list-sessions` | List available sessions |
| `--delete-session ` | Delete a session by index |
| `/new` | Start a new session within a session |
| `/clear` | Clear the Conversation History and start a new session |
| `/rename` | Rename the current session |
| `/branch` | Create a branch from the current session |
| `/resume`, `/continue` | Resume / continue a session |
| `/export` | Export the current conversation |
# View and Review Changes
## Overview
After Qoder modifies code, you typically need to check what it changed and conduct a code review. Qoder CLI offers two features: use `/diff` to view specific code diffs, and `/review` to perform a structured code review and identify fixable issues.
Both features are Git-based and must be used within a Git repository.
## View Changes (/diff)
Use `/diff` to view the code diff in the current workspace:
```shell
/diff
```
It displays the specific changes in modified and newly added (untracked) files, helping you quickly confirm what Qoder has changed.
## Review Changes (/review)
`/review` performs a code review on the changes to identify fixable issues. It can be used in two ways:
### Interactively Select Review Scope
When run without arguments, `/review` prompts you to select the review scope:
```shell
/review
```
The available review scopes include:
- **Current changes**: Review staged, unstaged, and untracked files.
- **Compare with Base Branch**: Select a local branch and review the changes in the current branch relative to it.
- **Specific commit**: Select a commit from the recent commit list for review (up to 100 commits are listed).
- **Custom instructions**: Enter custom review requirements.
### Provide Review Instructions Directly
When run with arguments, the arguments are passed directly to Qoder as review instructions:
```shell
/review Focus on checking concurrency safety and error handling in this change
```
## Review Scopes
| Scope | Review Content |
| :----------------------- | :---------------------------------------------------------------------- |
| Current Changes | Staged, unstaged, and untracked files in the workspace |
| Compare with Base Branch | Differences of the current branch relative to the selected local branch |
| Specific Commit | Changes introduced by the selected commit |
| Custom Instructions | Review according to your entered requirements |
When selecting "Compare with Base Branch", if the `main` or `master` branch exists locally, it is prioritized as the default base branch.
## Recommended Workflow
A typical "modify—view—review" workflow:
1. Have Qoder complete a modification.
2. Use `/diff` to quickly view what it changed.
3. Use `/review` to perform a structured review and identify potential issues.
4. Based on the review results, have Qoder make further corrections.
The "Compare with Base Branch" and "Specific Commit" scopes are particularly useful when you need to strictly vet the entire set of changes before committing.
> Both `/review` and `/diff` must be run in a Git repository. If you are not in a Git repository, or if no branches or commits are available, Qoder will display an appropriate prompt.
# Undo and Restore
## Overview
When collaborating with Qoder, you may want to return to a previous state—undoing a recent batch of changes or resuming the conversation from an earlier point to start over. Qoder CLI provides this capability through **Rewind**: it uses user messages in the conversation as checkpoints, allowing you to restore the conversation, file changes, or both to an earlier state.
## Rewind (/rewind)
Use `/rewind` to open the Rewind interface:
```shell
/rewind
```
The Rewind interface lists the checkpoints in the conversation (marked by the user messages you sent). After selecting a checkpoint, Qoder will display the impact of rewinding from that point and ask for your confirmation.
## What Can Be Restored
When confirming a rewind, you can choose the scope of the restoration:
- **Restore conversation and files** (default): Restores the conversation to the checkpoint and reverts all file changes made by Qoder after that point.
- **Restore conversation only**: Restores the conversation history to the checkpoint while leaving files in their current state.
- **Restore files only**: Reverts file changes made by Qoder after the checkpoint while leaving the conversation in its current state.
The Rewind interface displays the number of files affected and the lines added and deleted if files are restored (e.g., "Rewinding now will revert 3 files (+42 -17)"), helping you understand the scope of impact before confirming.
> File changes made through manual editing or Shell commands may not be reverted by Rewind. Rewind primarily targets changes made by Qoder through its file editing tools.
## How It Works
Qoder CLI records the file editing history during a session. Each checkpoint corresponds to a user message in the conversation, and Qoder tracks the file changes that occur afterward. When you choose to rewind to a specific checkpoint:
- If you choose to restore the conversation, the conversation history is truncated back to that checkpoint.
- If you choose to restore files, Qoder uses the recorded editing history to revert the relevant files to their state at the checkpoint.
If there are no file changes to revert for a particular checkpoint, the Rewind interface will clearly indicate "Will restore conversation, no file changes involved."
## When to Use
Rewind is suitable for the following scenarios:
- Qoder has gone in the wrong direction, and you want to return to the fork in the road to restate your requirements.
- The recent batch of changes is unsatisfactory, and you want to quickly revert them and try a different approach.
- You want to start over from an earlier point in the conversation to explore a different solution.
If you want to explore a new direction from a certain point while **keeping the original session**, you can also consider using Session Branches; see [Session Management](/cli/sessions). Rewind is "going back in time in place," whereas branching is "forking a new path from the past."
## Tips
- Pay attention to the file impact scope displayed in the interface before rewinding to ensure the content to be reverted meets your expectations.
- When dealing with important changes, it is safer to use it in conjunction with Git: committing at key points allows you to recover even if you go beyond the scope that Rewind can cover.
- Rewind only applies to the editing history recorded within the current session; cross-session changes or those made manually/via Shell are outside its scope.
# Select Models and Reasoning Effort
Qoder CLI includes world-class SOTA AI models and provides a flexible selection mechanism to help you find the right balance between development efficiency, output quality, and cost.
## Model Selection
### Tiered Models (Default)
The model tier selector provides four high-performance model pools for developers, each with a different balance between cost and performance. Like driving modes in a smart car, you can choose the right gear for each task.
| Tier | Description | Use Cases | Credit Usage |
| -------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------ | ------------ |
| Smart Routing (Auto) | Intelligently selects the most suitable model, balancing performance and cost | Most daily development work, recommended as the default | \~1.0x |
| Ultimate | Expert-level deep reasoning and thinking capabilities | Complex system design, high-difficulty problem analysis | \~1.6x |
| Performance | Advanced reasoning capabilities and high-quality output | Core feature implementation, architecture design, code refactoring | \~1.1x |
| Efficient | Standard reasoning capabilities with high cost-effectiveness | Basic code generation, unit tests, daily Q\&A | \~0.3x |
#### Credit Usage Comparison
The following table uses a single example task that consumes 10 Credits with Auto as the baseline. The other tiers are calculated using their respective multipliers to illustrate relative usage.
| Model Tier | Credit Usage Rate | Single Example Task Usage |
| ----------- | ----------------- | ------------------------- |
| Auto | \~1.0x | 10 Credits |
| Ultimate | \~1.6x | Approx. 16 Credits |
| Performance | \~1.1x | Approx. 11 Credits |
| Efficient | \~0.3x | Approx. 3 Credits |
A Credit rate is a billing multiplier; the table does not represent a fixed number of Credits charged per task. Actual usage also depends on input and output length, cache hits, thinking effort, context window, and tool calls. Refer to `/usage` for actual usage.
### Frontier Models (New Models)
The New Models tab shows the specific models currently available. It is suitable when you have a clear model preference or want to verify specific capabilities.
Available models, descriptions, Credit usage rates, and supported parameters may change with server-side model list updates. Refer to the `/model` interface and `--list-models` output for the current list.
> Currently, only some models are open for direct selection.
| Model Name | Capabilities and Parameters | Credit Usage Rate |
| ----------------- | --------------------------------------------------------------------------------------------- | ----------------- |
| Qwen3.8-Max | Reasoning, vision, thinking toggle, low / medium / xhigh effort, and 200K / 400K / 1M context | 0.5x |
| Qwen3.7-Max | Vision, thinking toggle, and 200K / 400K / 1M context | 0.5x |
| Qwen3.7-Plus | Vision, thinking toggle, and 200K / 400K / 1M context | 0.1x |
| Kimi-K3 | Vision, low / high / max effort, and 200K / 400K / 1M context | 0.8x |
| Kimi-K2.7-Code | Vision, 256K context, and Fast mode | 0.3x |
| GLM-5.3 | Reasoning, vision, low / high / max effort, and 200K / 400K / 1M context | 0.6x |
| GLM-5.2 | Reasoning, vision, thinking toggle, high / max effort, and 200K / 400K / 1M context | 0.6x |
| DeepSeek-V4-Pro | Reasoning, vision, thinking toggle, high / max effort, and 200K / 400K / 1M context | 0.8x |
| DeepSeek-V4-Flash | Reasoning, vision, thinking toggle, low / high / max effort, and 200K / 400K / 1M context | 0.3x |
| MiniMax-M3 | Vision and 200K / 400K / 1M context | 0.2x |
The rates in this table come from the current server-side model list's `price_factor`. Promotional periods and model parameters may affect the effective rate; refer to the `/model` parameter panel.
**Kimi-K2.7-Code** provides a **Fast** toggle in the parameter panel. Enabling it prioritizes response speed and may change Credit usage; refer to the parameter panel for the current rate.
### Custom Models (Custom)
Connect models from your own provider subscriptions. Qoder supports a curated list of providers. Configure your API key to start using them.
Qoder supports accessing third-party provider model resources via API keys.
**Applicable For**: Individual plan
**Supported Providers**: Alibaba Cloud Model Studio, DeepSeek, Z.ai, Kimi, MiniMax, Xiaomi MIMO
## Model Parameters
Some models support configurable parameters to better adapt to different task types. Available parameters depend on the current model. The CLI shows supported options in the `/model` model list and model parameter panel.
### Context Window
The context window controls the maximum context length available for the conversation. Common options include:
| Option | Description |
| ------ | ------------------------------------------------------------- |
| 200K | Standard context window, sufficient for most tasks |
| 400K | Extended context for larger codebases or longer conversations |
| 1M | Maximum context for extremely large-scale projects |
In TUI mode, type `/context-window` to open the model parameter panel and adjust the context window.
### Thinking Effort
Controls how deeply the model reasons before generating a response. Available options vary by model. After you select a model, the interface shows the levels supported by that model.
| Option | Description |
| ------ | ------------------------------------------------------- |
| low | Minimal reasoning, fastest response |
| medium | Moderate reasoning depth |
| high | Deep reasoning for complex tasks |
| xhigh | Deep analysis for high-difficulty problems |
| max | Maximum reasoning depth for the most complex challenges |
Use `/effort` in TUI mode to adjust the current model's thinking effort. Run it without arguments to open the model parameter panel, or pass a level directly:
```text
/effort high
/effort auto --session-only
/effort off
```
By default, changes are saved to `~/.qoder/settings.json`; add `--session-only` to apply them only to the current session.
### Fast Mode
Some models provide Fast mode to prioritize response speed. Credit usage may change after it is enabled. Refer to the model parameter panel for details.
```text
/fast on
```
### Supported Models
For parameter support in New Models, see the table above. Ultimate and Performance in the Default tiers also support context window, the thinking toggle, and thinking effort. Model parameters may change with server-side configuration; refer to the current parameter panel.
## Switching Models
### Switch in TUI
Type `/model` in TUI mode to open the model selector. The interface has three tabs: Default, New Models, and Custom.
```text
/model
```
`↑` / `↓` to navigate, `Tab` to switch tabs, `Enter` to confirm, `Esc` to close.
Your selection is automatically saved to `~/.qoder/settings.json` and persists across sessions.
### Command-Line Flags
Use the `--model`, `--reasoning-effort`, and `--context-window` flags to specify model settings at startup. These apply to the current session only and are not persisted:
```bash
qoder --model efficient # Efficient tier
qoder --model auto # Auto tier
qoder --reasoning-effort high
qoder --context-window 400000
```
### List Available Models
Use `--list-models` to print the models available to the current account without opening the TUI. This is useful for scripts and automation:
```bash
qoder --list-models
```
## Adding a Custom Model
1. Type `/model` and switch to the **Custom** tab
2. Select `Add custom model...` and press `Enter`
3. Follow the prompts to select Provider -> Model Type -> Model
4. Enter your API key and any other required fields
5. Once verified, the model is saved and ready to use
To delete a custom model, select it in the Custom tab and press `d`.
# view usage and quota
## Overview
Qoder CLI usage is metered in Credits. Use `/usage` to view your Plan and Credits usage for the current billing cycle, along with the duration and code change statistics for the current session. This helps you monitor your usage and avoid overages.
## View Usage
In an interactive session, enter:
```shell
/usage
```
Qoder will open the Usage Panel, displaying your current Plan and Credits information.
> Viewing usage requires valid account Authentication. If you are not signed in or have not set an Access Token, `/usage` will prompt you to complete Authentication first. For Authentication methods, see [Sign-in and Authentication](/cli/authentication).
## Usage Panel Contents
The Usage Panel includes the following information:
| Field | Description |
| :------------------- | :--------------------------------------------- |
| Plan | The Plan type of the current account |
| Plan Expiration Date | The expiration date of the current Plan |
| Plan Credits Used | Used / total Plan Credits |
| Add-on Credits Used | Used / total Add-on Credits |
| Org Resource Package | Usage of the Org Resource Package |
| Total Duration API | Cumulative time spent on Model API calls |
| Total Duration wall | Actual elapsed time since the session started |
| Total Code Changes | Lines added and deleted in the current session |
The Plan, expiration date, and various Credits are derived from your account quotas; API duration, wall clock duration, and code changes are statistics from the current session.
## How to Interpret
- **Credits usage** is displayed as "used / total". When the usage ratio approaches the limit, the panel uses color cues: reaching 80% displays a warning color, and reaching 95% displays an error color, helping you stay aware of your remaining Credits.
- **Total Duration API** reflects the actual computation time of the models, while **Total Duration wall** reflects the overall session duration, including your thinking and input time. The two are usually different.
- **Total Code Changes** counts the lines added and deleted by Qoder within the current session.
## Related
- To further analyze your Session History and usage patterns, see [Insights](/cli/insights).
- To check the overall Status of the CLI (version, Model, account, connectivity), use `/status`. See the [Slash commands reference](/cli/slash-reference).
# Insights
## Overview
Insights analyzes your Qoder CLI Session History to generate a visual HTML Report, helping you understand your usage patterns—when you are most active, the types of tasks you primarily work on, the Programming Languages involved, the Complexity Distribution of your tasks, and how your usage trends evolve over time.
It aggregates Metadata scattered across numerous sessions into holistic Insights, making it ideal for periodic reviews of personal or project development activities.
## Generate Report
In an interactive session, enter:
```shell
/insights
```
Qoder will analyze your Session History, generate an HTML Report, and open it in your default browser. Progress prompts are displayed during generation, and the file path of the report is printed upon completion.
## Analysis Dimensions
The Insights report covers the following dimensions:
- **Session Statistics**: Total number of sessions, total messages, and user messages.
- **Time distribution**: Activity distribution by hour (24-hour) and by day, reflecting your activity patterns throughout the day and over time.
- **Programming Language**: The Programming Languages involved and their proportions.
- **Topic category**: Distribution statistics of session topics.
- **Intent analysis**: Distribution statistics of session intents.
- **Complexity Distribution**: Distribution of tasks by low, medium, and high complexity.
- **Activity Pattern**: Active time periods and usage consistency.
- **Trend Analysis**: Activity trends over time.
## Data Source
Insights data is sourced from your local Session Log:
- **Session Metadata**: Such as start time, message count, etc.
- **Session Characteristics (facets)**: Such as topic, language, intent, complexity estimation, etc.
During analysis, the report aggregates this data and generates natural language insights and trend descriptions. The generated HTML Report is saved in a local temporary directory and opened in the browser.
## When to Use
- **Personal Review**: Understand the types of tasks you primarily work on over a period, and the languages and topics you invest in.
- **Activity Patterns**: Discover your most productive times of the day or your usage consistency.
- **Trend Observation**: Observe changes in usage volume and task complexity over time.
## Related
- To view billing-related information such as quota and session duration, see [view usage and quota](/cli/usage).
# Best Practices for Large Codebases
## Overview
This document summarizes best practices for making Qoder CLI work more efficiently, especially in large codebases and Monorepos. The core principle is simple: **prepare the information, constraints, and context Qoder needs in advance to minimize detours.**
## Write Effective Prompts
Clear prompts often save more time than multiple rounds of correction:
- **State goals and constraints clearly**: Specify not only what to do, but also what not to change and what rules must be followed.
- **Provide key context**: When dealing with specific files, interfaces, or conventions, name them directly to reduce Qoder's search overhead.
- **Focus on one thing at a time**: Break complex requirements into sequential, smaller steps rather than stacking all demands at once for better control.
- **Define acceptance criteria**: Clearly state "what counts as done" (e.g., a specific test passes, a command runs without errors) so Qoder can self-verify.
## Manage Context
The context window is limited, so it must be actively managed during long sessions:
- When switching to an unrelated new task, use `/clear` to clear historical context.
- When a long session reaches a point where context becomes tight, use `/compact` to compress history and retain key information.
- Write stable project conventions into `AGENTS.md` to avoid repeating explanations in every conversation. See [Memory](/cli/memory).
For details on context mechanisms and differences, see [How Memory Works](/cli/how-memory-works).
## Solidify Conventions with Project Instructions
For teams and large projects, `AGENTS.md` and rules are key to improving consistency:
- Use `/init` in the project root directory to generate `AGENTS.md`, documenting architecture, directory structure, common commands, and collaboration conventions.
- Use rule files under `/.qoder/rules/` to split instructions by topic (testing, API, security) to prevent a single `AGENTS.md` from becoming too bloated.
- When **strict** restrictions on certain commands or paths are needed, use permissions or Hooks instead of relying solely on instructions. See [Permissions](/cli/permissions) and [Hooks](/cli/hooks-reference).
## Large Codebase
When working in large repositories:
- **Start from a subdirectory**: Launch Qoder in the subdirectory you are working on (rather than the repository root) so it prioritizes loading project instructions and rules at that level. Project memory is searched upwards from the current directory. See [Memory](/cli/memory).
- **Narrow the exploration scope**: Name relevant modules or files directly to prevent Qoder from searching broadly across the entire repository.
- **Hierarchical project instructions**: Place respective `AGENTS.md` and rules in key subdirectories to give different modules their own context.
## Monorepo
A Monorepo typically contains multiple relatively independent packages or applications:
- **Organize project instructions by package**: Maintain `AGENTS.md` in each package directory, describing the package's responsibilities, dependencies, and conventions. When Qoder accesses a file in a package, it will load the instructions for that directory and its parent directories as needed.
- **Work within the target package**: When working on a specific package, launch from its directory or explicitly specify the working scope to reduce irrelevant context.
- **Work in parallel**: Use Worktrees to create independent workspaces for different packages or tasks to avoid interference. See [Handling Multiple Tasks in Parallel](/cli/parallel-tasks).
## Choose a Working Mode
Different tasks are suited to different working modes:
- **High impact or uncertain direction**: Use Plan to confirm the approach first. See [Plan Before Execution (Plan)](/cli/plan-mode).
- **Clear endpoint, hands-off completion**: Use Goal for continuous execution. See [Continuous Goal Completion (Goal)](/cli/goal).
- **Scripts and pipelines**: Use Headless Mode. See [Run in Scripts](/cli/run-in-scripts).
For a comprehensive guide on choosing a mode, see [Choosing the Right Working Mode](/cli/working-modes).
## Let Qoder Self-Verify
- Have Qoder proactively run tests or builds after modifying code to form an "implement-verify-correct" closed loop.
- Use `/diff` and `/review` to review changes after completion. See [Viewing and Reviewing Code Changes](/cli/review-changes).
- For significant changes, combine with Git commits and use rollbacks to restore when necessary. See [Reverting Changes and Restoring Sessions](/cli/undo-restore).
# Subagent
A Subagent is a specialized agent in Qoder CLI for handling a specific class of work. It can have its own system prompt, tool set, model configuration, permission mode, runtime limits, and hooks. Use Subagents to delegate focused work such as code exploration, implementation planning, API review, test authoring, and migration assessment.
## Quick Start
1. Run `/agents` in TUI to open the configuration panel.
2. Press `Tab` to switch to the `User` or `Project` tab.
3. Select `Create new agent...`, enter a Subagent description, and confirm.
4. After generation, invoke it directly in the conversation:
```text
Use the api-reviewer subagent to review this API design
```
## What a Subagent Is
Use a Subagent when a task spans many files, needs stable domain-specific criteria, or would otherwise fill the main conversation with search and analysis details. The main session understands the user goal and coordinates the work; the Subagent completes a clear subtask and returns its result to the main session.
Core benefits:
| Benefit | Description |
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Keep the main session focused | Each Subagent has its own conversation context, system prompt, tool registry, transcript, and compression flow. Its intermediate search and reasoning do not directly enter the main conversation. |
| Improve specialized task quality | Configure task-specific prompts, tool allowlists, tool denylists, MCP servers, models, permissions, and runtime limits so review, exploration, and planning tasks follow stable criteria. |
| Reuse team workflows | User-level and project-level Subagents can be reused repeatedly and shared with a project, giving teams a consistent workflow for recurring tasks. |
| Control tool and permission boundaries | Each Subagent can have its own tool set and permission mode, reducing the chance that a high-risk task uses the wrong capability. |
| Orchestrate complex work | Qoder CLI can dispatch independent Subagents in parallel. Independent work can also run in the background and notify the main session later. |
Core capabilities:
| Capability | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Isolated context | Each Subagent has its own conversation context, system prompt, tool registry, transcript, and compression flow. Its intermediate search and reasoning do not directly enter the main conversation. |
| Custom capability set | Configure task-specific prompts, tool allowlists, tool denylists, MCP servers, models, permissions, and runtime limits. |
| Concurrent execution | Qoder CLI can dispatch multiple independent Subagents in parallel. |
| Background execution | Independent work can run in the background and notify the main session later. |
| Workspace isolation | Use `worktree` isolation when a Subagent should run in a separate git worktree. |
If you already know the exact file or command, use the direct tool. Subagents are best for open-ended, multi-step work that needs judgment and synthesis.
## Built-In Subagents
Qoder CLI registers a set of built-in Subagents. The exact list in the `BuiltIn` tab of `/agents` can vary by version, runtime mode, and enabled features.
Common built-in Subagents:
| Name | Capability |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `general-purpose` | General research Subagent for complex search, multi-file analysis, call-path tracing, and multi-step work. When a dispatch omits the Subagent type, the agent tool defaults to this Subagent. |
| `Explore` | Fast read-only code exploration for finding files, searching symbols, and understanding existing implementations. It inherits available tools, removes write and control tools, and uses exploration-oriented model settings. |
| `Plan` | Read-only implementation planning for outlining the approach, critical files, sequencing, and architectural trade-offs before editing. |
Depending on mode and feature flags, you may also see:
| Name | When It Appears | Capability |
| ------------------ | --------------- | ------------------------------------------------------------------------------------------------------ |
| `qoder-guide` | Non-SDK mode | Answers Qoder CLI usage, configuration, Skills, Agents, MCP, and Hooks questions. |
| `statusline-setup` | TUI mode | Configures a custom status line. It may read shell configuration, create scripts, and update settings. |
Built-in Subagents are provided and maintained by Qoder CLI. They are not edited like user-level or project-level Subagents. To customize behavior, create a custom Subagent with a new name or the same name and rely on source priority.
## View and Use Subagents
### View Available Subagents
#### TUI
In TUI, enter:
```text
/agents
```
The `/agents` panel groups Subagents by source and lets you inspect details, create Subagents, enable or disable them, edit custom entries, and reload definitions. After changing `.qoder/agents/` or `~/.qoder/agents/`, run:
```text
/agents reload
```
#### Non-Interactive
In non-interactive environments, use:
```bash
qoder agents list
```
The list includes all discovered Subagents. When a Subagent is shadowed by a higher-priority source with the same name, the listing marks it as shadowed.
### Sources and Priority
Qoder CLI discovers Subagents from multiple sources. Same-name definitions override each other by priority, from low to high:
| Priority | Source | Entry | Description |
| -------- | -------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | Built-in | `BuiltIn` tab in `/agents` | Capabilities shipped with Qoder CLI. They are provided and maintained by Qoder CLI and are usually not edited directly. |
| 2 | User | `~/.qoder/agents/*.md` | User-level Subagents. They apply across this user's projects. |
| 3 | Project | `.qoder/agents/*.md` | Project-level Subagents. They apply to the current project, are suitable for project sharing, and depend on folder trust. |
| 4 | Plugin | Installed plugins | Subagents provided by plugins. The `Plugin` tab appears only when plugin Subagents exist, and they are usually maintained by the plugin. |
| 5 | Flag | `--agents` JSON | Temporary Subagents injected into the current process. They have the highest priority and only apply to this command or session. |
The highest-priority same-name definition is active; overridden definitions are marked as `shadowed` in `qoder agents list`.
### Explicit Invocation
#### TUI Mode
In a TUI conversation, the most stable way to invoke a Subagent is to name it directly in the input:
```text
Use the api-reviewer subagent to review this API design
```
You can also mention a loaded Subagent with `@` in TUI input:
```text
@api-reviewer review this API design and return only required changes
```
#### Headless Mode
In Headless mode, pass the same natural-language request through `qoder -p`:
```bash
qoder -p "Use the api-reviewer subagent to review this API design"
```
### Implicit Invocation
#### TUI Mode
In a TUI conversation, you can describe the task and let Qoder CLI match it against each Subagent's `description`:
```text
Review this API design
```
#### Headless Mode
In Headless mode, pass only the task description through `qoder -p`:
```bash
qoder -p "Review this API design"
```
If a specific Subagent must be used, name it explicitly; in TUI, you can also use `@name`.
### Use a Subagent as the Session Agent
`--agent` uses an already loaded Subagent as the main agent for the current session. In this mode, that definition's `initialPrompt` is used as the session's initial prompt.
#### TUI Mode
Specify `--agent` when starting TUI:
```bash
qoder --agent api-reviewer
```
After TUI starts, the current session uses `api-reviewer` as the main agent. Running an agent from the `/agents` panel does not switch the main session agent; it submits an `@agent-name` request for a single Subagent invocation.
#### Headless Mode
In Headless mode, use it together with `-p`:
```bash
qoder --agent api-reviewer -p "Review this API design"
```
### Orchestrate Multiple Subagents
Describe the Subagent execution order in natural language, and Qoder CLI will process the task according to that sequence.
#### TUI Mode
Enter the orchestration request directly in a TUI conversation:
```text
First use the general-purpose subagent to check the implementation approach, then use the api-reviewer subagent to review the API design
```
#### Headless Mode
In Headless mode, pass the same orchestration request through `qoder -p`:
```bash
qoder -p "First use the general-purpose subagent to check the implementation approach, then use the api-reviewer subagent to review the API design" --max-turns 10
```
For independent tasks, explicitly ask for parallel dispatch. For dependent work, describe the order as shown above. `--max-turns` limits the whole Headless query. To limit a single Subagent invocation, set `maxTurns` in that Subagent's configuration.
## Customize Subagents
### Create Persistent Local Subagent Definitions
#### Method 1: AI-Assisted Generation (Recommended)
This is the easiest way to create a Subagent. Describe what you need in natural language, and Qoder CLI generates a complete configuration file for you.
Steps:
1. Run `/agents` in TUI to open the configuration panel.
2. Press `Tab` to switch to the `User` or `Project` tab.
3. Select `Create new agent...` and press `Enter`.
4. Enter a Subagent description and press `Enter` to confirm.
```text
> /agents
------------------------------------------------------------------------------------------
Agents: User [Project] BuiltIn
-> Create new agent...
Agent list:
No project agents found.
Press Enter to select - Esc to exit - Tab to cycle tabs - Up/Down to navigate
```
After you enter a description, Qoder CLI generates the configuration:
```text
> /agents
------------------------------------------------------------------------------------------
Agents: User [Project] BuiltIn
Describe the agent:
> Help me review RESTful api design
Press Enter to select - Esc to exit - Tab to cycle tabs - Up/Down to navigate
```
When generation finishes, you can find and refine the configuration file in the selected directory:
```bash
# Project-level (Project tab)
.qoder/agents/
# User-level (User tab)
~/.qoder/agents/
```
Tip: start with AI-assisted generation, then iterate until the Subagent matches your specific workflow. This gives you a strong customizable baseline.
#### Method 2: Write Configuration Manually (Advanced)
If you need full control over Subagent configuration, create a Markdown configuration file manually:
```bash
# Project-level, only active in the current project, suitable for version control
.qoder/agents/api-reviewer.md
# User-level, active across this user's projects
~/.qoder/agents/api-reviewer.md
```
Markdown files must start with YAML frontmatter. Frontmatter declares configuration; the Markdown body is the local Subagent's system prompt.
```markdown
---
name: api-reviewer
description: Review API designs, endpoint naming, request methods, status codes, error responses, and versioning.
tools: [Read, Grep, Glob]
disallowedTools: [Write, Edit]
permissionMode: default
model: inherit
maxTurns: 8
timeoutMins: 10
color: cyan
---
You are an API design reviewer.
Focus on:
- Resource naming and URL structure
- Request method semantics
- Status code and error response consistency
- Pagination, filtering, and versioning
Return concise findings grouped by severity. Include concrete examples when possible.
```
To run a Subagent in a separate worktree, add this to its frontmatter:
```yaml
isolation: worktree
```
The filename does not define the Subagent name. The actual name comes from the frontmatter `name` field.
### Inject Temporary Subagents with `--agents`
`--agents` is useful for Headless runs, scripts, and one-off automation. It accepts a JSON object whose keys are Subagent names and whose values are definitions. Subagents injected with `--agents` only exist for the current process and have the highest priority for name conflicts.
```bash
qoder \
--agents '{"api-reviewer":{"description":"Review API designs","prompt":"You are an API reviewer.","tools":["Read","Grep","Glob"],"maxTurns":6}}' \
-p "Use the api-reviewer subagent to review docs/api.yaml"
```
`--agents` uses the `prompt` field as the system prompt. The current JSON schema supports `description`, `prompt`, `tools`, `disallowedTools`, `mcpServers`, `model`, `effort`, `color`, `maxTurns`, `initialPrompt`, `skills`, and `permissionMode`. Use Markdown configuration when you need `timeoutMins`, `temperature`, `hooks`, `memory`, `background`, or `isolation`.
## Configure Subagents
### Select a Scope
When creating or injecting a custom Subagent, choose one of these scopes:
| Scope | Configuration Entry |
| ------- | ---------------------- |
| Project | `.qoder/agents/*.md` |
| User | `~/.qoder/agents/*.md` |
| Flag | `--agents` |
### Configure Tools
`tools` and `disallowedTools` can be comma-separated strings or string arrays. String arrays can use either YAML inline-array syntax or YAML block-list syntax:
```yaml
tools: Read,Grep,Glob
```
```yaml
tools: [Read, Grep, Glob]
```
```yaml
tools:
- Read
- Grep
- Glob
```
Common tool names include `Read`, `Grep`, `Glob`, `Bash`, `Write`, `Edit`, `WebFetch`, `WebSearch`, and `Agent`.
MCP tools use fully qualified names:
```yaml
tools:
- mcp__docs__search
- mcp__docs__*
- mcp__*
```
To allow a Subagent to call only specific other Subagents, use the `Agent(name)` expression:
```yaml
tools:
- Read
- Grep
- Agent(Explore, Plan)
```
To prevent further Subagent dispatch entirely, disable `Agent`:
```yaml
disallowedTools: [Agent]
```
Tool handling order is: register allowed tools from `tools`, then remove tools listed in `disallowedTools`. MCP tools must be discovered through `mcpServers` or global MCP configuration and also allowed by `tools` before the Subagent can use them.
### Configure MCP
Reference an already configured MCP server:
```yaml
mcpServers:
- docs
```
Or define an MCP server inline for this Subagent:
```yaml
mcpServers:
docs:
command: ./scripts/docs-mcp
args: ["--stdio"]
include_tools: ["search", "read"]
```
`mcpServers` supports both array and object formats. Inline server fields:
| Field | Meaning |
| ------------------ | ----------------------------------------------- |
| `command` | Command that starts a stdio MCP server. |
| `args` | Command argument array. |
| `env` | Environment variables passed to the MCP server. |
| `cwd` | MCP server working directory. |
| `url` / `http_url` | Remote MCP server URL. |
| `headers` | Remote request headers. |
| `tcp` | TCP connection address. |
| `type` | Transport type, `sse` or `http`. |
| `timeout` | Connection or call timeout. |
| `trust` | Whether to trust this MCP server. |
| `description` | Server description. |
| `include_tools` | Include only specific MCP tools. |
| `exclude_tools` | Exclude specific MCP tools. |
### Define Hooks
`hooks` in Subagent frontmatter are scoped to that Subagent session. Supported events include `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `Stop`, `SubagentStart`, `SubagentStop`, and `Notification`.
`hooks` does not support string shorthand. The value of each event must be a matcher array, and each matcher declares one or more hooks through its own `hooks` array.
Inside a Subagent, `Stop` is remapped to `SubagentStop`, so it fires when that Subagent finishes rather than when the main session ends.
```yaml
hooks:
PreToolUse:
- matcher: Bash
hooks:
- type: command
command: ./scripts/check-subagent-command.sh
timeout: 30
statusMessage: Checking command
Stop:
- hooks:
- type: command
command: ./scripts/subagent-finished.sh
```
Each event contains matchers; each matcher has a `hooks` array with these hook types:
| `type` | Required Field | Description |
| --------- | -------------- | -------------------------------------------------------------------------------------------------- |
| `command` | `command` | Run a local command. Optional `shell`, `timeout`, `if`, and `statusMessage`. |
| `http` | `url` | Call an HTTP endpoint. Optional `headers`, `allowedEnvVars`, `timeout`, `if`, and `statusMessage`. |
| `prompt` | `prompt` | Run a model check from a prompt. Optional `model`, `timeout`, `if`, and `statusMessage`. |
| `agent` | `prompt` | Run an independent hook agent. Optional `model`, `timeout`, `if`, and `statusMessage`. |
The frontmatter schema accepts `once`, but ordinary Subagent frontmatter does not preserve one-shot hook semantics. If you need one-shot behavior, implement it in the hook command or external state.
### Configure Permission Modes
`permissionMode` controls approval behavior for Subagent tool calls.
| Value | Meaning |
| ------------------- | ---------------------------------------------------------------------------------------- |
| `default` | Use the default permission policy and ask when needed. |
| `acceptEdits` | Automatically accept edit operations. |
| `bypassPermissions` | Skip permission prompts. If security policy disables it, it is demoted to `acceptEdits`. |
| `dontAsk` | Do not proactively ask; operations that require asking are denied. |
| `auto` | Use automatic policy classification. |
| `plan` | Enter this Subagent's own planning state, useful for read-only planning. |
Use the canonical values above in public configuration. Runtime parsing also tolerates case and separator variants; `yolo` is parsed as `bypassPermissions` for compatibility, but `bypassPermissions` is the recommended spelling.
Notes:
- If `permissionMode` is omitted, the Subagent inherits the current parent session mode.
- If the parent session is already in `acceptEdits`, `bypassPermissions`, or `auto`, the Subagent cannot make itself stricter through its own configuration.
- `plan` does not affect the main session's plan state. It only applies inside the Subagent's isolated context.
### Override Existing Subagents with `settings.json`
`settings.json` cannot create new Subagents. It only overrides Subagents that have already been discovered. Current overrides support enabled state, model configuration, runtime limits, tool allowlists, and appended MCP servers.
```json
{
"agents": {
"overrides": {
"api-reviewer": {
"enabled": true,
"tools": ["Read", "Grep", "Glob"],
"runConfig": {
"maxTurns": 6,
"maxTimeMinutes": 10
},
"modelConfig": {
"model": "auto",
"generateContentConfig": {
"temperature": 0.2
}
},
"mcpServers": {
"docs": {
"command": "./scripts/docs-mcp",
"args": ["--stdio"]
}
}
}
}
}
}
```
Common uses:
- Set `"enabled": false` to hide a Subagent temporarily.
- Give one Subagent a different model and temperature.
- Limit maximum turns or maximum runtime for automation.
- Tighten the tool set without editing the original Markdown.
- Append MCP servers to an existing local Subagent.
Plugin-provided Subagents apply an additional safety policy: `hooks`, `mcpServers`, and `permissionMode` are removed, and `isolation` is preserved only when it is `worktree`.
### Local Subagent Full Field Reference
The fields below apply to Markdown frontmatter. Unknown fields are ignored.
| Field | Required | Values | Meaning |
| ----------------- | :------: | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | Yes | Non-empty string | Subagent name. Prefer clear, stable names that are easy to mention in natural language. |
| `description` | Yes | Non-empty string | Description of when to use this Subagent. Qoder CLI uses it for selection. |
| `background` | No | Boolean | Whether the Subagent should launch in the background by default. |
| `color` | No | `red`, `blue`, `green`, `yellow`, `purple`, `orange`, `pink`, `cyan` | Color shown while the Subagent is running in TUI. |
| `disallowedTools` | No | String or string array | Tool denylist, applied after tools are registered. |
| `effort` | No | `low`, `medium`, `high`, `xhigh`, `max`, or positive integer | Reasoning effort or budget. |
| `hooks` | No | Hook configuration object | Frontmatter hooks scoped only to this Subagent session. |
| `initialPrompt` | No | String | Initial prompt when this definition is used through `--agent` as the session agent. Normal Subagent calls do not inject it as the task prompt. |
| `isolation` | No | Prefer `worktree` | Isolation mode. `worktree` runs the Subagent in a separate git worktree. Omitted means the default workspace. |
| `kind` | No | `local` | Type. Only local Subagents are currently supported. |
| `maxTurns` | No | Positive integer | Maximum conversation turns for one Subagent invocation. |
| `mcpServers` | No | Server-name array, inline server object, or a mix | Extra MCP discovery for this Subagent. Actual use is still controlled by `tools` and `disallowedTools`. |
| `memory` | No | `user`, `project`, `local` | Persistent memory scope for this Subagent. Only active when global automatic memory is enabled. |
| `model` | No | Any model name or model alias; common values include `inherit`, `auto`, `lite`, `efficient`, `performance` | Model used by this Subagent. Omitted means `inherit`, using the current session model. |
| `permissionMode` | No | `default`, `acceptEdits`, `bypassPermissions`, `dontAsk`, `auto`, `plan` | Permission mode for this Subagent. Omitted means inherit the current parent session mode. |
| `skills` | No | String or string array | Restrict which Skills this Subagent can use. |
| `temperature` | No | Number | Model temperature. When omitted, the loader writes a default temperature configuration. |
| `timeoutMins` | No | Positive integer | Maximum runtime for one Subagent invocation, in minutes. |
| `tools` | No | String or string array; supports `*` | Tool allowlist. Omitted means use the current available tool set; `*` means all tools. |
## Test the Result
After creating or editing a Subagent, verify it in this order:
1. Run `/agents reload` or start a new session.
2. Confirm it appears under the expected source in `/agents` or `qoder agents list`.
3. Check that `description` clearly explains when it should be used.
4. Invoke it by explicit name once:
```text
Use the api-reviewer subagent to review this API:
POST /login
GET /logout
```
5. If it is configured as read-only, ask it not to modify files and confirm no write operation appears.
6. If it has `disallowedTools`, ask for a blocked capability and confirm it chooses another path or explains the restriction.
7. If it uses MCP, confirm the target MCP tool is discovered and not blocked by `tools`.
8. If it uses `background` or background execution, confirm the launch result returns immediately. When the main session has no other work, it shows a waiting state, and the completion notification automatically returns to the main session.
If it is not invoked, first use the explicit name or `@name`. If it is still unavailable, check load errors in the `/agents` panel.
## Best Practices
- Give each Subagent one clear responsibility instead of mixing review, implementation, testing, and release work.
- Write `description` for selection, and write the body prompt for the Subagent itself. Both should be specific.
- Start with read-only tools, then add `Edit`, `Write`, or `Bash` only when needed.
- For higher-risk Subagents, set `maxTurns`, `timeoutMins`, and an explicit `permissionMode`.
- Use `isolation: worktree` when a Subagent needs an isolated working copy, then inspect the returned worktree path and actual diff.
- If the Subagent depends on MCP tools, configure both `mcpServers` and `tools` so the tools are discovered and allowed.
- Use project-level Subagents for team-shared standards and user-level Subagents for personal preferences or cross-project workflows.
- Test with explicit invocation before relying on implicit selection.
- For plugin-shipped Subagents, do not depend on `hooks`, `mcpServers`, or `permissionMode`, because the plugin safety policy removes those fields.
## FAQ
### How is a Subagent different from the main session?
A Subagent runs in an independent context with its own system prompt, tool set, runtime limits, and permission declaration. Its result is returned to the main session, which can summarize or continue the work.
### Why does my project-level Subagent not appear?
Confirm the file is at `.qoder/agents/.md`, the frontmatter includes at least `name` and `description`, and the current project is trusted. Then run `/agents reload` and check load errors in the `/agents` panel.
### Why did a same-name Subagent not take effect?
Higher-priority sources override lower-priority sources. The order is Built-in \< User \< Project \< Plugin \< Flag. Use `qoder agents list` to see shadowed entries.
### What is the difference between `description` and the body prompt?
`description` explains when to call the Subagent and affects selection. The body prompt is the system prompt the Subagent sees after it is invoked and affects how it performs the task.
### Can multiple Subagents run at the same time?
Yes. Qoder CLI can dispatch independent Subagents concurrently. For dependent work, describe the order in your prompt.
### Can a Subagent call another Subagent?
Yes, if the `Agent` tool remains available. Use `Agent(name)` or `Agent(name1, name2)` to allow only specific Subagents. Use `disallowedTools: [Agent]` to prevent further dispatch.
### Why can my Subagent not use the MCP tool I configured?
First confirm the MCP server is discovered through `mcpServers` or global MCP configuration. Then confirm `tools` allows the fully qualified MCP tool name. `mcpServers` discovers tools; it does not automatically authorize every MCP tool.
### Why did the Subagent permission mode not become stricter?
If the parent session is already in `acceptEdits`, `bypassPermissions`, or `auto`, the Subagent cannot make itself stricter through `permissionMode`. If `permissionMode` is omitted, it inherits the current parent session mode.
### Where do background Subagent results appear?
When a Subagent runs in the background, the main session first receives a launch result and can continue work that does not depend on it. If there is no other work, the main conversation shows a waiting state to indicate that the session is still running. When the task finishes, its result automatically returns to the main session for synthesis or follow-up work. In TUI, use `/tasks` to view its status and result or to stop it while it is still running.
### Can I edit built-in or plugin Subagents?
Built-in and plugin Subagents are not meant to be edited directly. Create a user-level or project-level Subagent instead. If you use the same name to override behavior, pay attention to source priority and plugin safety policy.
# MCP Servers
Qoder CLI can connect to Model Context Protocol (MCP) servers to use external tools and data sources. After a server is added, its tools become available to the agent in interactive and non-interactive sessions.
## Quick Start
Add a stdio MCP server with `qoder mcp add`. The command after `--` is the server process Qoder CLI should launch.
```shell
qoder mcp add playwright -- npx -y @playwright/mcp@latest
```
Stdio servers start automatically with the CLI. If Qoder CLI is already running, use `/mcp reload` to rediscover MCP servers and tools; new sessions discover them on startup.
## Server Types
Use `-t` to choose the MCP transport type.
| Type | Use when |
| :------ | :--------------------------------------------------------------- |
| `stdio` | The MCP server runs as a local command. |
| `sse` | The MCP server is exposed through a Server-Sent Events endpoint. |
| `http` | The MCP server is exposed through an HTTP endpoint. |
| `ws` | The MCP server is exposed through a WebSocket endpoint. |
If you do not specify a type, local command servers should use the default stdio behavior.
When the shell command prefix is enabled, Qoder CLI launches stdio servers through the configured executable wrapper. The wrapper receives the original server executable and arguments as one shell-quoted argument and must execute it while preserving stdio and the exit status. The configured value must be a single executable path. This setting does not affect `sse`, `http`, or `ws` servers.
## Scopes
Use `-s` to choose where the MCP server configuration is stored.
| Scope | Use when |
| :-------- | :----------------------------------------------------------------------------------------------------- |
| `user` | You want the server available to your local account across projects. |
| `local` | You want the server available only for the current project on your machine. This is the default scope. |
| `project` | You want the server configuration shared with the project. |
MCP server configuration is stored in these files:
```md
# User-level configuration.
~/.qoder/settings.json
# Local project-specific configuration. Usually not committed.
${project}/.qoder/settings.local.json
# Project-level configuration. Usually committed with the project.
${project}/.mcp.json
```
## Manage Servers
List configured servers:
```shell
qoder mcp list
```
Remove a server:
```shell
qoder mcp remove playwright
```
## Recommended Servers
Common MCP servers include:
```shell
qoder mcp add context7 -- npx -y @upstash/context7-mcp@latest
qoder mcp add deepwiki -- npx -y mcp-deepwiki@latest
qoder mcp add chrome-devtools -- npx chrome-devtools-mcp@latest
```
## Permissions
MCP tools still pass through Qoder CLI permissions. In the default mode, calling an MCP tool usually asks for confirmation. You can approve a specific tool, approve all tools from one MCP server, or configure rules in settings.
MCP tool names commonly use this format:
```text
mcp____
```
Examples:
```json
{
"permissions": {
"allow": [
"mcp__context7__*"
],
"deny": []
}
}
```
## Troubleshooting
If an MCP tool is not available:
- Run `qoder mcp list` and confirm the server is configured.
- If Qoder CLI is already running, run `/mcp reload` after adding or changing a server.
- Confirm the command after `--` works in your terminal.
- For `npx`-based servers, confirm Node.js and network access are available.
- Check permission prompts if the server is connected but tool calls are blocked.
# Skills
A Skill is a folder containing a `SKILL.md` that teaches Qoder CLI how to do something specific: reviewing PRs using your team’s standards, generating commit messages in your preferred format, or querying your company’s database schema. When you ask Qoder CLI something that matches a Skill’s purpose, Qoder CLI automatically applies it.
**Key features**:
- **Intelligent invocation**: The model autonomously decides when to use a Skill based on user requests and Skill descriptions
- **Modular design**: Each Skill focuses on solving a specific type of task
- **Flexible extension**: Supports both user-level and project-level custom Skills
## Quick Start
This example creates a Skill for generating API documentation.
### 1. Create the Skill directory
Create a directory in your user-level Skills folder. User-level Skills are available across all your projects. You can also create project-level Skills in `.qoder/skills/` to share with your team.
```bash
# Create user-level Skills directory
mkdir -p ~/.qoder/skills/api-doc-generator
```
### 2. Write SKILL.md
Every Skill needs a `SKILL.md` file, starting with YAML metadata between `---` markers that must include `name` and `description`, followed by Markdown instructions.
Create `~/.qoder/skills/api-doc-generator/SKILL.md`:
```markdown
---
name: api-doc-generator
description: Generate comprehensive API documentation from code. Use when creating API docs, documenting endpoints, or generating OpenAPI specs.
---
# API Documentation Generator
When generating API documentation:
1. Identify all API endpoints and routes
2. Document request/response formats
3. Include authentication requirements
4. Add example requests and responses
5. Generate OpenAPI/Swagger specification if needed
```
### 3. Load and verify the Skill
New sessions load Skills at startup. If Qoder CLI is already running, use `/skills reload` to refresh the discovered Skills. Verify successful loading:
```
What Skills are available?
```
Or use the command:
```
/skills
```
The conversation should show `api-doc-generator` with its description.
### 4. Test the Skill
Open an API route file in your project and ask a question matching the Skill's description:
```
Generate documentation for this API
```
Qoder CLI applies the `api-doc-generator` Skill and generates relevant API documentation. If not triggered, try rephrasing using keywords from the description.
## How Skills Work
Skills can be loaded via command or automatically invoked by the model. The model decides which Skill to use based on request content—no explicit specification needed.
1. Discovery: At startup, Qoder CLI loads each Skill's name and description, enabling fast startup while letting the model understand each Skill's applicable scenarios.
2. Activation: When a request matches a Skill's description, the model requests to use that Skill and loads the full `SKILL.md`. Some Skills can run without an extra confirmation; Skills that need additional capabilities may ask for approval. Write descriptions that include keywords users commonly use.
3. Execution: The model executes according to Skill instructions, loading referenced files or running scripts as needed.
### Where Skills live
Storage location determines a Skill's availability:
| Location | Path | Scope | Use cases |
| ------------- | --------------------------------------- | ----------------------------- | ---------------------------------------------------------- |
| User-level | `~/.qoder/skills/{skill-name}/SKILL.md` | All projects for current user | Personal workflows, experimental Skills, personal tools |
| Project-level | `.qoder/skills/{skill-name}/SKILL.md` | Current project only | Team workflows, project-specific knowledge, shared scripts |
When names conflict, user-level Skills override project-level Skills.
### Skills vs Commands
Core difference: **Skills are triggered automatically** based on your request, while Commands require you to type `/command-name` explicitly.
| Feature | Skill | Command |
| -------------- | ------------------------------------------------- | ------------------------ |
| Trigger method | Automatic (model-based) or manual (`/skill-name`) | Manual (`/command-name`) |
| Primary use | Domain expertise, complex workflows | Quick preset tasks |
| Storage | `skills/` directory | `commands/` directory |
| Permission | May require approval depending on the Skill | Not required |
> **Note:** Internally, Skills convert to a special Command type and share the same execution mechanism.
## When to Use Skills
**Use Skills for**:
- **Complex specialized tasks**: Workflows requiring domain expertise (code review, PDF processing, API design)
- **Standardized processes**: Tasks following fixed steps (commit conventions, deployment flows)
- **Team knowledge sharing**: Package best practices for sharing
- **Repetitive work**: Frequently executed tasks requiring specialized guidance
**Use Commands for**:
- Simple, quick operations
- Tasks requiring explicit user triggering
- Tasks not needing complex prompt guidance
## Create a Skill
### Choose Storage Location
| **Location** | Path | **Applies to** |
| ------------- | --------------------------------------- | ----------------------------- |
| User-level | `~/.qoder/skills/{skill-name}/SKILL.md` | All projects for current user |
| Project-level | `.qoder/skills/{skill-name}/SKILL.md` | Current project only |
> **Tip:** User-level Skills override project-level Skills with the same name.
**Create the directory**:
```bash
# User-level
mkdir -p ~/.qoder/skills/my-skill-name
# Project-level
mkdir -p .qoder/skills/my-skill-name
```
### Organize Directory Structure
**Directory structure example**:
```
{skill-name}/
├── SKILL.md # Required: main file
├── REFERENCE.md # Optional: reference
├── EXAMPLES.md # Optional: documentation examples
├── scripts/ # Optional: helper scripts
│ └── helper.py
└── templates/ # Optional: template files
└── template.txt
```
Reference auxiliary files in `SKILL.md` for progressive disclosure:
```markdown
For better usage,see [REFERENCE.md]. For examples, see [EXAMPLES.md].
Run the helper script:
python scripts/helper.py input.txt
```
### Write SKILL.md
Create `SKILL.md` with YAML frontmatter and Markdown content:
```markdown
---
name: skill-name
description: Brief description of functionality and when to use
---
# Skill Name
## Instructions
Provide clear step-by-step guidance.
## Examples
Show specific usage examples.
```
**Frontmatter fields**:
| Field | Required | Description | Constraints |
| ------------- | -------- | --------------------------------------------------------- | ------------------------------------------------------ |
| `name` | Yes | Unique Skill identifier | Lowercase letters, numbers, hyphens only; max 64 chars |
| `description` | Yes | Functional description for model to determine when to use | Max 1024 chars |
> **Important:** The `description` field is critical for the model to discover when to use your Skill. Include what it does and when to use it. See "Best Practices" section for details.
## Use Skills
### Automatic Trigger
Describe your need directly, the model automatically determines whether to use a Skill:
```
Analyze the errors in this log file
```
The model recognizes and invokes the `log-analyzer` Skill.
### Manual Trigger
Use `/skill-name` to trigger manually:
```
/log-analyzer
```
### View Available Skills
**In CLI**:
```
What Skills are available?
```
**Through file system**:
```bash
# List user-level Skills
ls ~/.qoder/skills/
# List project-level Skills
ls .qoder/skills/
# View SKILL.md files
ls ~/.qoder/skills/*/SKILL.md
ls .qoder/skills/*/SKILL.md
```
## Update and Delete
### Update a Skill
Edit `SKILL.md` directly. New sessions load the updated Skill on startup. If Qoder CLI is already running, run `/skills reload` to refresh the discovered Skills.
### Delete a Skill
Delete the Skill directory:
```bash
# User-level
rm -rf ~/.qoder/skills/my-skill
# Project-level
rm -rf .qoder/skills/my-skill
```
> **Warning:** Deleting a Skill directory permanently removes all files with no recovery.
## Best Practices
### Keep Skills Focused
Each Skill should focus on one specific domain or task type.
**Recommended**:
- `log-analyzer` - Log analysis
- `security-auditor` - Security auditing
- `database-migrator` - Database migration
**Not recommended**:
- `coding-helper` - Too broad
### Write Clear Descriptions
The `description` should include: what the Skill does, when to use it, and key trigger words.
**Comparison**:
```yaml
# Not recommended: vague
description: Helps with logs
# Recommended: specific
description: Analyze log files to identify errors, patterns, and performance issues. Use when debugging logs, investigating errors, or monitoring application behavior.
```
### Test Before Sharing
Before sharing, ensure:
- Skill triggers in expected scenarios
- Instructions are clear
- Common edge cases are covered
### Document Version Changes
Add version history to SKILL.md:
```markdown
## Version History
- v2.0.0 (2026-10-01): Breaking API changes
- v1.1.0 (2026-09-15): New features
- v1.0.0 (2026-09-01): Initial release
```
## Troubleshooting
### Skill Not Triggering
**Check file location**:
```bash
ls ~/.qoder/skills/*/SKILL.md
ls .qoder/skills/*/SKILL.md
```
Confirm SKILL.md exists with correct path.
**Check YAML format**:
View SKILL.md to verify frontmatter has no syntax errors (indentation, quote matching).
**Check description specificity**:
Use clear, specific descriptions:
```yaml
# Recommended: clear purpose and trigger conditions
description: Analyze log files to identify errors, patterns, and performance issues. Use when debugging logs, investigating errors, or monitoring application behavior.
# Not recommended: vague
description: For logs
```
### Skill Execution Errors
**Check dependency availability**:
The CLI automatically installs required dependencies when needed (or requests permission).
**Check script permissions**:
```bash
chmod +x .qoder/skills/my-skill/scripts/*.py
```
### Multiple Skills Conflict
When the CLI confuses similar Skills, use different trigger terms in descriptions to distinguish them.
## Examples
### Example 1: Simple Skill
Analyze log files and diagnose issues.
**Directory structure**:
```
log-analyzer/
└── SKILL.md
```
**SKILL.md**:
```markdown
---
name: log-analyzer
description: Analyze log files to identify errors, patterns, and performance issues. Use when debugging logs, investigating errors, or monitoring application behavior.
---
# Log Analyzer
## Instructions
1. Read the log file to understand its format
2. Identify and categorize issues:
- Error patterns and stack traces
- Warning messages
- Performance bottlenecks
- Unusual patterns or anomalies
3. Provide summary with:
- Issue severity and frequency
- Root cause analysis
- Recommended solutions
## Analysis tips
- Focus on recent critical errors first
- Look for recurring patterns
- Check timestamp correlations across entries
```
### Example 2: Use multiple files
Database migration and version management tool.
**Directory structure**:
```
database-migrator/
├── SKILL.md
├── MIGRATION_GUIDE.md
├── ROLLBACK.md
└── scripts/
├── generate_migration.py
├── validate_schema.py
└── backup_db.sh
```
**SKILL.md**:
````markdown
---
name: database-migrator
description: Generate and manage database migrations, schema changes, and data transformations. Use when creating migrations, modifying database schema, or managing database versions. Requires sqlalchemy and alembic packages.
---
# Database Migrator
## Quick start
Generate a new migration:
```bash
python scripts/generate_migration.py --name add_user_table
```
For detailed migration patterns, see [MIGRATION_GUIDE.md](MIGRATION_GUIDE.md).
For rollback strategies, see [ROLLBACK.md](ROLLBACK.md).
## Workflow
1. **Analyze changes**: Compare current schema with desired state
2. **Generate migration**: Create migration file with up/down operations
3. **Validate**: Run `python scripts/validate_schema.py` to check syntax
4. **Backup**: Execute `scripts/backup_db.sh` before applying
5. **Apply**: Run migration in staging environment first
6. **Verify**: Check data integrity after migration
## Requirements
Install required packages:
```bash
pip install sqlalchemy alembic psycopg2-binary
```
## Safety checks
- Always backup before migrations
- Test rollback procedures
- Validate data integrity after changes
- Use transactions for atomic operations
````
# Plugins
A plugin is a directory in Qoder CLI that bundles commands, sub-agents, Skills, Hooks, MCP servers, and other extensions for installation, enable/disable management, and sharing. A plugin directory may contain one or more of these resources, and the CLI auto-discovers and loads them after installation.
## Quick Start
The following example creates a minimal plugin containing a single Skill and installs it from a local directory.
### 1. Create the plugin directory
```bash
mkdir -p ~/my-plugin/.qoder-plugin
mkdir -p ~/my-plugin/skills/hello
```
### 2. Write the manifest
Declaring a `plugin.json` is recommended for every plugin so it has stable metadata; at minimum include `name` (see [Manifest Fields](#manifest-fields) below):
`~/my-plugin/.qoder-plugin/plugin.json`:
```json
{
"name": "my-plugin",
"version": "0.1.0",
"description": "My first plugin"
}
```
### 3. Add a Skill
`~/my-plugin/skills/hello/SKILL.md`:
```markdown
---
name: hello
description: Greet the user. Use when the user says "say hi".
---
# Hello Skill
Greet the user warmly.
```
### 4. Install
```bash
qoder plugins install ~/my-plugin
```
After seeing `Plugin "my-plugin@local" installed successfully. Run /plugins reload to apply.`, restart the CLI or run `/plugins reload` in the TUI to start using the Skill.
## Plugin Directory Layout
`.qoder-plugin/plugin.json` is the recommended location for the manifest. When omitted, the CLI still loads the directory by convention and uses the directory name as the plugin name. Convention directories are **auto-discovered when present, otherwise ignored**.
```
my-plugin/
├── .qoder-plugin/
│ └── plugin.json # Recommended: manifest (declares name/version/etc.)
├── commands/ # Custom commands (.md files or subdirectories)
├── agents/ # Custom sub-agents
├── skills/ # Custom Skills
├── hooks/
│ └── hooks.json # Hook configuration
├── output-styles/ # Output styles
├── bin/ # Plugin executables
└── .mcp.json # MCP servers shipped with this plugin
```
Convention directory behavior:
| Directory / File | Purpose |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
| `commands/` | Register custom slash commands; same structure as `~/.qoder/commands/` |
| `agents/` | Register custom sub-agents |
| `skills/` | Register Skills; same structure as `~/.qoder/skills/` |
| `hooks/hooks.json` | Hook configuration; uses the `{ "hooks": ... }` wrapper, where the inner `hooks` value matches the `hooks` field in `settings.json` |
| `output-styles/` | Custom output styles |
| `bin/` | Plugin executables |
| `.mcp.json` | MCP server declarations bundled with the plugin |
Agents shipped in `agents/` can also declare `isolation: worktree`, which is useful for implementation Subagents that should run in an isolated copy.
## Manifest Fields
Only `name` is required in `plugin.json`; other fields are optional.
| Field | Required | Description |
| ------------- | -------- | ------------------------------------------------------------------------------------------- |
| `name` | Yes | Unique plugin identifier; cannot contain spaces; kebab-case recommended (e.g., `my-plugin`) |
| `version` | No | Semantic version (e.g., `1.0.0`) |
| `description` | No | Brief description |
| `author` | No | Author information |
| `homepage` | No | Documentation or homepage URL |
| `repository` | No | Source repository URL |
| `license` | No | SPDX license identifier (e.g., `MIT`) |
| `keywords` | No | Tags for discovery and categorization |
> Advanced: the manifest can also explicitly declare `commands` / `agents` / `skills` / `hooks` / `outputStyles` to override the default directory conventions or use inline content (note the manifest field uses camelCase `outputStyles`, while the convention directory remains `output-styles/`). When not declared, the CLI auto-discovers via the conventions above.
## Installation Scope
Plugins can be installed at three scopes:
| Scope | Description | Use case |
| --------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| `user` | Globally available; applies to all of the current user's projects (default) | Personal frequently-used plugins |
| `project` | Applies only to the current project; written to project-level `settings.json`, can be committed to git for team sharing | Team-shared, project-specific plugins |
| `local` | Applies only to the current project; written to project-local `settings.local.json`, recommended to add to `.gitignore` | Local experimental plugins |
## Commands
Plugin commands live under the `qoder plugins` subcommand group, aliased as `plugin`.
### Install: `plugins install`
Install a plugin from a local directory path:
```bash
qoder plugins install ~/my-plugin
qoder plugins install ./relative/path/to/plugin
qoder plugins install /abs/path/to/plugin --scope project
```
| Argument / Option | Description |
| --------------------- | ------------------------------------------------------------ |
| `` | Local plugin directory path (absolute, relative, or `~/...`) |
| `-s, --scope ` | Installation scope: `user` (default), `project`, `local` |
After installation, restart the CLI or run `/plugins reload` in the TUI to apply changes.
### Uninstall: `plugins uninstall`
```bash
qoder plugins uninstall my-plugin
qoder plugins uninstall my-plugin --scope project --keep-data
```
Aliases: `remove` / `rm`.
| Argument / Option | Description |
| --------------------- | ------------------------------------------------------------- |
| `` | Installed plugin name |
| `-s, --scope ` | Scope to uninstall from: `user` (default), `project`, `local` |
| `--keep-data` | Preserve the plugin's data directory |
### Enable / Disable: `plugins enable` / `plugins disable`
```bash
qoder plugins enable my-plugin
qoder plugins disable my-plugin
qoder plugins enable my-plugin --scope project
qoder plugins disable --all
```
| Argument / Option | Description |
| --------------------- | ---------------------------------------------------------------- |
| `` | Installed plugin name |
| `-s, --scope ` | Scope to write to; auto-detected if omitted |
| `-a, --all` | (`disable` only) Disable all enabled plugins in the chosen scope |
Enable / disable is implemented by updating the `enabledPlugins` field in the corresponding `settings.json`. Disabled plugins are not loaded in new sessions.
### List: `plugins list`
```bash
qoder plugins list
qoder plugins list --json
qoder plugins list --plugin-dir ./local-plugins ./more-plugins
```
| Option | Description |
| ------------------------------ | ---------------------------------------------------------------------------- |
| `--json` | Output as JSON |
| `-o, --output-format ` | `text` or `json` (equivalent to `--json`) |
| `--plugin-dir ` | Additional directories to scan and merge into the listing (does not install) |
### Validate: `plugins validate`
Validate that a local plugin directory matches the conventions; useful during development:
```bash
qoder plugins validate ~/my-plugin
```
The command lists the commands, Skills, Hooks, and other components it discovers, and prints a notice when no convention subdirectory exists. Note: `validate` does not fail in that case — but `plugins install` for a local plugin requires at least one recognizable component or resource (either a convention directory or a resource explicitly declared in the manifest).
> **Recommended**: always declare `name`, `version`, etc. in `.qoder-plugin/plugin.json`. This is the recommended way to organize a Qoder plugin — without it, the plugin can only be identified by its directory name in `plugins list`, `enabledPlugins`, and other places, which is fragile across environments.
## The `enabledPlugins` Setting
Enable / disable state is stored in the `enabledPlugins` field of `settings.json`:
```json
{
"enabledPlugins": {
"my-plugin@local": true,
"another-plugin@local": false
}
}
```
- `true`: enables the plugin
- `false`: explicitly disables the plugin
> The configuration key must match the installed plugin ID exactly (locally installed plugins have IDs of the form `name@local`). Run `plugins list` to see each plugin's identifier.
Prefer `plugins enable` / `plugins disable` over hand-editing this field — the commands handle scope selection, dependency resolution, and other details for you.
## Writing Plugin Hooks
A plugin may declare its own Hooks in `hooks/hooks.json`. The file uses a **wrapped** shape: a top-level object with a `hooks` field whose value matches the `hooks` field in `settings.json`:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "\"${QODER_PLUGIN_ROOT}\"/scripts/check.sh"
}
]
}
]
}
}
```
> Note this differs from `settings.json`: `settings.json` uses the bare `hooks` field, while a plugin's `hooks/hooks.json` requires the extra `{ "hooks": ... }` wrapper.
When executed, plugin Hooks receive two extra environment variables:
| Variable | Description |
| ------------------- | ------------------------------------------------------------------------------------------------------ |
| `QODER_PLUGIN_ROOT` | Installation root of the current plugin |
| `QODER_PLUGIN_DATA` | Data directory of the current plugin (separate from the install dir to preserve state across upgrades) |
See [Hooks](./hooks) for more on writing Hooks.
## Marketplace
A marketplace is a centralized distribution source for plugins. By adding a marketplace, you can browse and install published plugins without managing local directories manually.
### Add a Marketplace
Multiple source formats are supported:
```bash
# Git repository (HTTPS / SSH)
qoder plugins marketplace add https://git.example.com/org/my-marketplace.git
qoder plugins marketplace add git@git.example.com:org/my-marketplace.git
# Owner/repo shorthand (for supported git hosts)
qoder plugins marketplace add org/my-marketplace
# Local directory
qoder plugins marketplace add /path/to/marketplace
# URL pointing to a marketplace.json
qoder plugins marketplace add https://example.com/marketplace.json
```
### List Configured Marketplaces
```bash
qoder plugins marketplace list
qoder plugins marketplace list --json
```
### Update a Marketplace
Refresh the plugin catalog from the source:
```bash
# Update a specific marketplace
qoder plugins marketplace update my-marketplace
# Update all marketplaces
qoder plugins marketplace update
```
### Remove a Marketplace
```bash
qoder plugins marketplace remove my-marketplace
```
Removing a marketplace also uninstalls all plugins that were installed from it.
### Install Plugins from a Marketplace
Once a marketplace is added, install plugins by name:
```bash
qoder plugins install hello-world
```
The CLI searches all configured marketplaces and installs the plugin. The resulting plugin ID takes the form `name@marketplace-name`.
### List Available Plugins
```bash
qoder plugins list --available --json
```
Returns all plugins from configured marketplaces that are not yet installed.
### Update Installed Marketplace Plugins
```bash
qoder plugins update hello-world
```
# Hooks
Hooks let you intercept the Agent's main execution flow at key points in Qoder CLI while remaining decoupled from the CLI itself. Common use cases include: blocking dangerous operations before tool execution, sending desktop notifications when a task completes, automatically running lint after writing files, and more.
Hooks are defined via JSON configuration files — no code changes required. Edit the config file and they take effect immediately.
## Quick Start
The following example demonstrates how to use a Hook to block dangerous commands — automatically preventing execution when the Agent attempts to run `rm -rf`.
**Step 1: Create the script**
```bash
mkdir -p ~/.qoder/hooks
cat > ~/.qoder/hooks/block-rm.sh << 'EOF'
#!/bin/bash
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command')
if echo "$command" | grep -q 'rm -rf'; then
echo "Dangerous command blocked: $command" >&2
exit 2
fi
exit 0
EOF
chmod +x ~/.qoder/hooks/block-rm.sh
```
**Step 2: Edit the configuration file**
Add the following to `~/.qoder/settings.json`:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/block-rm.sh"
}
]
}
]
}
}
```
**Step 3: Verify**
Start Qoder CLI and ask the Agent to run a command containing `rm -rf`. The Hook will block execution and report back to the Agent.
## Configuration
### Configuration File Locations
Hook configuration is loaded from the following three files. All three sources are **loaded and merged together** (hooks for the same event do not override each other):
```
~/.qoder/settings.json # User level, applies to all projects
${project}/.qoder/settings.json # Project level, applies to the current project; can be committed to git for team sharing
${project}/.qoder/settings.local.json # Project level (local), recommended to add to .gitignore
```
### Configuration Format
```json
{
"hooks": {
"EventName": [
{
"matcher": "match condition",
"hooks": [
{
"type": "command",
"command": "command to execute",
"timeout": 600
}
]
}
]
}
}
```
A single event can contain multiple matcher groups, and each group can contain multiple hook entries.
**Group (HookDefinition) fields:**
| Field | Required | Description |
| --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `matcher` | No | Match condition; matches all if omitted |
| `hooks` | Yes | Array of hook entries in this group |
| `async` | No | When `true`, all hooks in the group run in the background without blocking the current operation; results are injected as additional context in the next model turn |
### Hook Entry Types
Each hook entry declares its type via `type`. Different types support different fields.
#### command (run a shell command)
```json
{
"type": "command",
"command": "~/.qoder/hooks/check.sh",
"timeout": 600,
"shell": "bash",
"env": { "FOO": "bar" }
}
```
| Field | Required | Description |
| --------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `command` | Yes | The shell command to execute |
| `timeout` | No | Timeout in seconds, default 600 |
| `shell` | No | `"bash"` or `"powershell"`; system default if omitted |
| `env` | No | Extra environment variables, merged with the system environment |
| `if` | No | Conditional filter, e.g. `"ToolName"` or `"ToolName(arg_pattern)"`, fires only when the tool name / argument matches |
| `async` | No | When `true`, this single hook runs in the background; overrides the group-level `async` |
| `asyncRewake` | No | When `true`, runs in the background; if it exits with code 2, the CLI builds a system reminder from stderr/stdout/error and wakes the model — useful for long-running checks |
| `rewakeMessage` | No | With `asyncRewake`, overrides the prefix of the injected system message |
| `rewakeSummary` | No | With `asyncRewake`, overrides the one-line summary (max 300 chars) |
| `once` | No | When `true`, the hook is removed from the registry after its first successful execution; only effective for session-scoped hooks |
| `statusMessage` | No | Custom description shown in the spinner / status line |
| `args` | No | Optional argv array. When set, the hook runs in exec form (no shell). See [Exec form vs Shell form](#exec-form-vs-shell-form) below. |
##### Referencing placeholders in `command`
Placeholders like `${QODER_PROJECT_DIR}` and `${QODER_PLUGIN_ROOT}` are exported as environment variables in the hook's subprocess (see [Environment Variables](#environment-variables)). Under `bash`, the shell expands them at runtime — the command template is not pre-substituted by the CLI. Recommended writing styles:
- **Double-quote the placeholder** (recommended): `"${QODER_PLUGIN_ROOT}"/scripts/hook.sh`. Paths containing spaces or shell metacharacters (`'`, `$`, backticks, etc.) parse correctly as a single token.
- **Plain shell variable syntax**: `"$QODER_PLUGIN_ROOT/scripts/hook.sh"`. Equivalent to the form above when wrapped in double quotes.
- **Unquoted** (not recommended): `${QODER_PLUGIN_ROOT}/scripts/hook.sh`. POSIX shells still apply field splitting and pathname expansion to unquoted parameter expansions, so paths containing spaces or `*` will be split or globbed.
> The preflight check that warns when `${QODER_PLUGIN_ROOT}` or `${QODER_PLUGIN_DATA}` is used outside a plugin only matches the `${...}` form (to avoid false positives on literal `$VAR` text). Plugin authors who want preflight coverage should prefer the `${...}` form.
Under `powershell`, `${QODER_PROJECT_DIR}`, `${QODER_PLUGIN_ROOT}`, and `${QODER_PLUGIN_DATA}` are substituted into the command template by the CLI before invocation (because PowerShell uses `$env:NAME` rather than `${NAME}` for environment access).
##### Exec form vs Shell form
Command hooks support two execution forms:
- **Shell form** (default): `command` is a shell snippet. The CLI runs `bash -c ""` (or PowerShell). Pipes, redirection, glob expansion, and `${VAR}` env-var expansion all work.
- **Exec form** (when `args` is set): `command` is the path/name of a single executable, and each element of `args` is one literal argv entry. The CLI runs the binary directly without a shell — no quoting, splitting, or globbing is performed. The `shell` field is ignored when `args` is set.
```json
{
"type": "command",
"command": "/usr/bin/python3",
"args": ["${QODER_PLUGIN_ROOT}/scripts/check.py", "--strict"]
}
```
Choose based on what the hook needs:
- **Default to shell form** — env-var expansion handles paths containing spaces, single quotes, `$`, backticks, etc. when you wrap placeholders in double quotes (`"${QODER_PLUGIN_ROOT}"/scripts/check.sh`).
- **Use shell form when** the hook needs pipes (`grep | tee`), redirection (`>`), globs (`*.json`), or other shell features.
- **Use exec form when** the path or arguments contain shell metacharacters that would require complex quoting, or when you want to be certain no shell parsing happens.
Caveats for exec form on Windows:
- `.bat`/`.cmd` scripts cannot be exec'd directly. Use `{"command": "cmd.exe", "args": ["/c", "script.bat"]}` instead.
- MSYS / Cygwin programs receive argv in their own conventions; consult the target program's documentation for any argument quoting it expects internally.
When the shell command prefix is enabled, only shell-form hooks that use a bash-compatible shell run through the configured executable wrapper. Exec-form hooks and PowerShell hooks are launched directly and are not prefixed.
#### http (send an HTTP request)
The hook input is POSTed as JSON to the URL; the response is expected to be a JSON HookOutput.
```json
{
"type": "http",
"url": "https://example.com/hook",
"headers": { "Authorization": "Bearer ${MY_TOKEN}" },
"timeout": 600
}
```
| Field | Required | Description |
| ------------------------------- | -------- | ------------------------------------------------------------------------------------------------------ |
| `url` | Yes | URL that receives the POST |
| `headers` | No | Custom request headers; values support `${ENV_VAR}` interpolation |
| `allowedEnvVars` | No | Whitelist of environment variables allowed to be interpolated in `headers`; all are allowed if omitted |
| `timeout` | No | Timeout in seconds, default 600 |
| `if` / `once` / `statusMessage` | No | Same as command |
#### prompt (single LLM call)
Evaluate the hook event via an isolated single-turn LLM call. The model returns `{ ok, reason }`: `ok=true` means allow, `ok=false` means block, and `reason` is shown to the Agent on block.
```json
{
"type": "prompt",
"prompt": "Decide whether the command is safe; when not safe, return ok=false and provide a reason.",
"model": "haiku",
"timeout": 30
}
```
| Field | Required | Description |
| ------------------------------- | -------- | -------------------------------------------------------------------------------------- |
| `prompt` | Yes | The prompt template sent to the evaluator. The serialized event JSON is appended to it |
| `model` | No | Model override; uses the session default if omitted |
| `timeout` | No | Timeout in seconds, default 30 |
| `if` / `once` / `statusMessage` | No | Same as command |
**Isolated evaluation.** The evaluator runs in its own session, sees only your `prompt` and the current event, and has no view into the main conversation's prior tool calls, model output, or anything that happened earlier. Write conditions that can be decided from the event itself; rules that depend on conversation history cannot be evaluated here — use a `command` hook that maintains its own state, or an `agent` hook that can inspect the filesystem.
#### agent (sub-agent verification)
Spawn a sub-agent to verify a condition. The sub-agent must call the `StructuredOutput` tool with `{ ok: boolean, reason?: string }`: `ok=true` allows, `ok=false` blocks.
```json
{
"type": "agent",
"prompt": "Review the following changes: $ARGUMENTS",
"tools": ["Read", "Grep"],
"maxTurns": 50,
"timeout": 60
}
```
| Field | Required | Description |
| ------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `prompt` | Yes | Verification prompt; supports the `$ARGUMENTS` placeholder (replaced with the hook input JSON) |
| `tools` | No | Whitelist of tools the sub-agent may use. Inherits all available tools when omitted, but tools unsafe inside hooks (recursive Agent calls, plan-mode tools, interactive prompts, etc.) are filtered out automatically |
| `maxTurns` | No | Max agentic turns, default 50 |
| `model` | No | Model override |
| `timeout` | No | Timeout in seconds, default 60 |
| `if` / `once` / `statusMessage` | No | Same as command |
**Isolated evaluation.** Like `prompt`, the sub-agent runs in its own session and cannot see the main conversation history. The difference is tool access: it can read files, grep the codebase, and run checks, making it suitable when verification must inspect real state.
### Matcher and `if` Rules
`matcher` (group level) filters when a hook fires. Different events match against different fields (see each event description) — typically tool names, event triggers, or sources:
| Syntax | Meaning | Example |
| ------------------ | --------------------- | ------------------------------------- |
| Omitted or `"*"` | Match all | All tools fire |
| Exact value | Exact match | `"Bash"` matches only the Bash tool |
| `\ | ` separated | Match multiple values | `"Write\ | Edit"` matches Write or Edit |
| Regular expression | Regex match | `"mcp__.*"` matches all MCP tools |
`if` (entry level) is a finer per-hook filter, of the form `"ToolName"` or `"ToolName(arg_pattern)"`:
- The tool-name part reuses the same matching logic as `matcher` (so regex and `|` are supported).
- The `arg_pattern` inside parentheses uses **glob matching** (not regex), and is checked against the tool's primary argument (e.g., Bash's `command`, file tools' `file_path`).
Examples:
| `if` value | Meaning |
| --------------- | -------------------------------------------------------------- |
| `"Bash"` | Fires when the tool is Bash |
| `"Bash(git *)"` | Fires when the tool is Bash and the command starts with `git ` |
| `"Edit(*.ts)"` | Fires when the tool is Edit and `file_path` matches `*.ts` |
## Writing Hook Scripts
Hook scripts receive JSON input via stdin and control behavior through exit codes and stdout. This section describes the input/output format common to all events. Event-specific fields are listed in [Event Reference](#event-reference).
### Input
Hook scripts receive JSON data via **stdin**. All events include the following common fields:
| Field | Description |
| ----------------- | ----------------------------------------------------- |
| `session_id` | Current session ID |
| `transcript_path` | Path to the current transcript file |
| `cwd` | Current working directory |
| `hook_event_name` | Name of the triggered event |
| `permission_mode` | Current permission mode (when the event provides one) |
| `agent_id` | Current agent ID (when the event provides one) |
| `agent_type` | Current agent type (when the event provides one) |
Different events append additional fields on top of these (see each event description).
Parse input with `jq`:
```bash
#!/bin/bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.tool_name')
```
### Output
Hooks control behavior through exit codes and stdout.
#### Exit codes
- `0`: success; stdout is parsed according to the rules below.
- `2`: blocking; stderr content is fed back to the Agent (only effective for events that support blocking).
- Other values: non-blocking error; stdout is ignored, stderr is written to diagnostic logs, the main flow continues.
#### Common stdout JSON fields
When exit is 0 and stdout is valid JSON, the CLI parses it according to the fields below; otherwise stdout is treated as plain text (only `SessionStart` / `UserPromptSubmit` inject plain-text stdout into the conversation as additional context).
| Field | Description |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `continue` | When `false`, requests stopping subsequent execution |
| `stopReason` | With `continue: false`, explains the reason to the Agent |
| `suppressOutput` | When `true`, do not display the hook output to the user |
| `systemMessage` | A hook system message shown to the user only — it is NOT injected into the model context |
| `decision` | `"allow"` or `"deny"`, event-specific decision; `"deny"` is equivalent to exit 2. To request user authorization (`"ask"`), use `PreToolUse`'s `hookSpecificOutput.permissionDecision` instead |
| `reason` | Reason for the decision; shown to the user / model |
| `hookSpecificOutput` | Container for event-specific fields (see each event) |
Event-specific fine-grained control fields (such as `PreToolUse`'s `permissionDecision` or `PostToolUse`'s `updatedToolOutput`) live inside `hookSpecificOutput`. **When emitting `hookSpecificOutput`, you must include `hookEventName`** — otherwise the entire JSON output is rejected and the TUI shows ` hook error: hookSpecificOutput is missing required field "hookEventName"`. Example:
```json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "ask"
}
}
```
### Environment Variables
The following environment variables are available when hook scripts execute:
| Variable | Description |
| ------------------- | ------------------------------------------------------- |
| `QODER_PROJECT_DIR` | Working directory of the current project |
| `QODER_PLUGIN_ROOT` | Plugin root directory when the hook comes from a plugin |
| `QODER_PLUGIN_DATA` | Plugin data directory when the hook comes from a plugin |
## Event Reference
Events are grouped by purpose. For each event, the matcher field, additional stdin fields, blocking support, and available `hookSpecificOutput` fields are listed.
### Overview
| Event | matcher matches | exit 2 blocks | Key input fields |
| -------------------- | ------------------------------------------- | ----------------------------------- | ------------------------------------------------ |
| `SessionStart` | `source` (startup/resume/clear/compact/new) | — | `source`, `model` |
| `SessionEnd` | `reason` | — | `reason` |
| `UserPromptSubmit` | — | ✅ | `prompt` |
| `PreToolUse` | tool name | ✅ | `tool_name`, `tool_input` |
| `PostToolUse` | tool name | — | `tool_name`, `tool_input`, `tool_response` |
| `PostToolUseFailure` | tool name | — | `tool_name`, `error`, `error_type` |
| `PermissionRequest` | tool name | — | `tool_name`, `tool_input` |
| `PermissionDenied` | tool name | — | `tool_name`, `tool_input`, `reason` |
| `Stop` | — | ✅ | `stop_hook_active`, `last_assistant_message` |
| `StopFailure` | `error_type` | — | `error_type`, `error` |
| `SubagentStart` | agent type | — | `agent_id`, `agent_type` |
| `SubagentStop` | agent type | ✅ | `agent_id`, `agent_type`, `stop_hook_active` |
| `PreCompact` | `trigger` | ✅ | `trigger`, `custom_instructions` |
| `PostCompact` | `trigger` | — | `trigger`, `compact_summary` |
| `Notification` | `notification_type` | — | `notification_type`, `message` |
| `InstructionsLoaded` | `load_reason` | — | `file_path`, `memory_type`, `load_reason` |
| `ConfigChange` | `source` | ✅ (except `policy_settings` source) | `source`, `file_path` |
| `CwdChanged` | — | — | `old_cwd`, `new_cwd` |
| `FileChanged` | filename basename | — | `file_path`, `event` |
| `WorktreeCreate` | — | non-zero exit fails | `name` |
| `WorktreeRemove` | — | — | `worktree_path` |
| `Elicitation` | `mcp_server_name` | ✅ | `mcp_server_name`, `message`, `requested_schema` |
| `ElicitationResult` | `mcp_server_name` | ✅ | `mcp_server_name`, `action`, `content` |
### Session Lifecycle
#### SessionStart
Triggered when a session starts.
**matcher field:** Session source
| matcher value | Trigger scenario |
| ------------- | ---------------------------------- |
| `startup` | New session started |
| `resume` | Existing session resumed |
| `clear` | Reset via `/clear` |
| `compact` | After context compaction completes |
| `new` | New session (other sources) |
**Additional input fields:**
```json
{
"source": "startup",
"model": "Auto"
}
```
**hookSpecificOutput:** `additionalContext` (context injected into the conversation)
> When the hook returns plain text (not JSON), the stdout is also injected into the conversation as context.
#### SessionEnd
Triggered when a session ends.
**matcher field:** End reason
| matcher value | Trigger scenario |
| ----------------------------- | ------------------------------------ |
| `clear` | Ended via `/clear` |
| `resume` | Switched to another session |
| `logout` | User logged out |
| `prompt_input_exit` | User exited input (Ctrl+D, etc.) |
| `bypass_permissions_disabled` | Bypass-permissions mode was disabled |
| `other` | Other reasons |
**Additional input fields:**
```json
{
"reason": "prompt_input_exit"
}
```
#### UserPromptSubmit
Triggered after the user submits a prompt and before the Agent processes it. Can prevent the prompt from entering the conversation.
**Additional input fields:**
```json
{
"prompt": "Write a sorting function for me"
}
```
**Blocking:** exit 2 rejects the prompt; stderr is shown to the user.
**hookSpecificOutput:**
- `additionalContext`: injected alongside the prompt
- `sessionTitle`: a suggested session title
> When the hook returns plain text (not JSON), the stdout is also injected into the conversation as context.
### Tool Calls
#### PreToolUse
Triggered before tool execution. Can block tool execution or modify the input.
**matcher field:** Tool name (e.g. `Bash`, `Write`, `Edit`, `Read`, `Glob`, `Grep`; MCP tool names like `mcp__server__tool`)
**Additional input fields:**
```json
{
"tool_name": "Bash",
"tool_input": {"command": "rm -rf /tmp/build"},
"tool_use_id": "toolu_01ABC123"
}
```
> For MCP tools, `mcp_context` (with `server_name`, `tool_name`, connection info) and `original_request_name` are also included.
**Blocking:** exit 2; stderr is returned to the Agent as an error.
**hookSpecificOutput:**
| Field | Description |
| -------------------------- | ------------------------------------------------------------------------------------ |
| `permissionDecision` | `"allow"` / `"deny"` / `"ask"`, equivalent to top-level `decision`; takes precedence |
| `permissionDecisionReason` | Reason; takes precedence over top-level `reason` |
| `updatedInput` | Modified tool input that replaces the original `tool_input` |
| `additionalContext` | Extra context injected into the conversation |
#### PostToolUse
Triggered after a tool executes successfully.
**matcher field:** Tool name
**Additional input fields:**
```json
{
"tool_name": "Write",
"tool_input": {"file_path": "/path/to/file.ts", "content": "..."},
"tool_response": {"success": true, "bytes_written": 1024},
"tool_use_id": "toolu_01ABC123"
}
```
> `tool_response` is an object whose shape depends on the tool. MCP tools also receive `mcp_context` / `original_request_name`.
**hookSpecificOutput:**
| Field | Description |
| ---------------------- | -------------------------------------------------------------------------- |
| `updatedToolOutput` | Replaces the tool response (works for any tool) |
| `updatedMCPToolOutput` | Replaces only MCP tool responses (lower priority than `updatedToolOutput`) |
| `additionalContext` | Extra context injected into the conversation |
#### PostToolUseFailure
Triggered after a tool execution fails.
**matcher field:** Tool name
**Additional input fields:**
```json
{
"tool_name": "Bash",
"tool_input": {"command": "npm test"},
"tool_use_id": "toolu_01ABC123",
"error": "Command exited with non-zero status code 1",
"error_type": "execution_failed",
"is_interrupt": false
}
```
**hookSpecificOutput:** `additionalContext`
#### PermissionRequest
Triggered when a tool requires user authorization. Can auto-allow, deny, or modify the input.
**matcher field:** Tool name
**Additional input fields:**
```json
{
"tool_name": "Bash",
"tool_input": {"command": "rm -rf node_modules"},
"permission_suggestions": []
}
```
**hookSpecificOutput:** `decision` object whose fields depend on `behavior`.
`behavior: "allow"` (allow execution; optionally rewrite input or persist permissions):
```json
{
"behavior": "allow",
"updatedInput": { "command": "..." },
"updatedPermissions": []
}
```
| Field | Description |
| -------------------- | ----------------------------------------------------------- |
| `behavior` | Must be `"allow"` |
| `updatedInput` | Modified tool input that replaces the original `tool_input` |
| `updatedPermissions` | Persisted permission rule updates |
`behavior: "deny"` (reject execution; optionally show a message):
```json
{
"behavior": "deny",
"message": "...",
"interrupt": false
}
```
| Field | Description |
| ----------- | ------------------------------------------------------------------ |
| `behavior` | Must be `"deny"` |
| `message` | Message shown to the user |
| `interrupt` | Whether to interrupt the current operation and surface to the user |
> `PermissionRequest` hooks do not support `"ask"` behavior. To prompt the user interactively, use `PreToolUse`'s `permissionDecision: "ask"` instead.
#### PermissionDenied
Triggered when the permission classifier denies a tool call. The hook can request a retry.
**matcher field:** Tool name
**Additional input fields:**
```json
{
"tool_name": "Bash",
"tool_input": {"command": "..."},
"tool_use_id": "toolu_01ABC123",
"reason": "Auto mode classifier blocked this call"
}
```
**hookSpecificOutput:** `retry: true` requests a retry of the tool call.
### Agent Flow
#### Stop
Triggered when the main Agent finishes responding with no pending tool calls. Can prevent the Agent from stopping and let it continue working.
**Additional input fields:**
```json
{
"stop_hook_active": false,
"last_assistant_message": "..."
}
```
| Field | Description |
| ------------------------ | ------------------------------------------------------------------------------------------ |
| `stop_hook_active` | Whether the current turn is being driven by a Stop hook (use this to avoid infinite loops) |
| `last_assistant_message` | The last assistant message before stopping |
**Blocking:** exit 2; stderr is injected into the conversation as a message and the Agent continues working.
**hookSpecificOutput:** `clearContext: true` to clear the conversation context.
#### StopFailure
Triggered when the Agent stops unexpectedly due to an error. Notification only — output and exit code are ignored.
**matcher field:** `error_type` (e.g. `rate_limit`, `server_error`)
**Additional input fields:**
```json
{
"error_type": "rate_limit",
"error": "...",
"error_details": "...",
"last_assistant_message": "..."
}
```
`error_type` values: `rate_limit` / `authentication_failed` / `billing_error` / `invalid_request` / `server_error` / `max_output_tokens` / `unknown`.
#### SubagentStart
Triggered when a sub-agent starts.
**matcher field:** Agent type name
**Additional input fields:**
```json
{
"agent_id": "a1b2c3d4",
"agent_type": "task"
}
```
**hookSpecificOutput:** `additionalContext`
#### SubagentStop
Triggered when a sub-agent completes. Can prevent the sub-agent from stopping (similar to `Stop`).
**matcher field:** Agent type name
**Additional input fields:**
```json
{
"agent_id": "a1b2c3d4",
"agent_type": "task",
"stop_hook_active": false,
"agent_transcript_path": "...",
"last_assistant_message": "..."
}
```
**Blocking:** exit 2; stderr is injected into the sub-agent's conversation.
**hookSpecificOutput:** `clearContext: true` to clear the sub-agent's context.
### Context Compaction
#### PreCompact
Triggered before context compaction. Can block compaction.
**matcher field:** Trigger method
| matcher value | Trigger scenario |
| ------------- | ----------------------------------------------------------------- |
| `manual` | User runs `/compact` manually |
| `auto` | Triggered automatically when the context window is near its limit |
**Additional input fields:**
```json
{
"trigger": "manual",
"custom_instructions": "Preserve all tool call results"
}
```
**Blocking:** exit 2 prevents this compaction.
#### PostCompact
Triggered after context compaction completes.
**matcher field:** Trigger method (same as PreCompact)
**Additional input fields:**
```json
{
"trigger": "manual",
"compact_summary": "Compaction summary..."
}
```
**hookSpecificOutput:** `additionalContext`
### Notifications
#### Notification
Triggered when a user-facing notification is emitted (permission requests, idle prompts, elicitation, etc.).
**matcher field:** Notification type
| matcher value | Trigger scenario |
| ---------------------- | ---------------------------- |
| `permission_prompt` | Tool permission request |
| `idle_prompt` | Idle prompt |
| `auth_success` | Successful authentication |
| `elicitation_dialog` | MCP elicitation dialog opens |
| `elicitation_response` | User responds to elicitation |
| `elicitation_complete` | Elicitation flow completes |
**Additional input fields:**
```json
{
"notification_type": "permission_prompt",
"message": "Agent is requesting permission to run: rm -rf node_modules",
"title": "Permission Required",
"details": {}
}
```
**hookSpecificOutput:** `additionalContext`
### Context and Configuration Loading
#### InstructionsLoaded
Triggered when an instruction / memory file is loaded. Notification only — output and exit code are ignored.
**matcher field:** `load_reason` (e.g. `session_start`, `include`)
**Additional input fields:**
```json
{
"file_path": "/abs/path/AGENTS.md",
"memory_type": "project",
"load_reason": "session_start",
"globs": ["**/AGENTS.md"],
"trigger_file_path": "...",
"parent_file_path": "..."
}
```
`load_reason` values: `session_start` / `nested_traversal` / `path_glob_match` / `include` / `compact`.
#### ConfigChange
Triggered when a configuration file changes during a session.
**matcher field:** Config source
| matcher value | Trigger scenario |
| ------------------ | ----------------------------------------------------- |
| `user_settings` | User-level `~/.qoder/settings.json` |
| `project_settings` | Project-level `${project}/.qoder/settings.json` |
| `local_settings` | Project-local `${project}/.qoder/settings.local.json` |
| `policy_settings` | Policy configuration |
| `skills` | Skill directory changes |
| `agents` | Custom agent directory changes |
**Additional input fields:**
```json
{
"source": "user_settings",
"file_path": "/abs/path/settings.json"
}
```
**Blocking:** exit 2 prevents the change from being applied to the current session. **Exception**: when `source` is `policy_settings`, hooks still fire for audit purposes but the change is enforced and cannot be blocked.
### Working Directory and Files
#### CwdChanged
Triggered when the working directory changes.
**Additional input fields:**
```json
{
"old_cwd": "/old",
"new_cwd": "/new"
}
```
**hookSpecificOutput:**
| Field | Description |
| ------------------- | --------------------------------------------------------- |
| `additionalContext` | Context injected into the conversation |
| `watchPaths` | Absolute paths to register with the `FileChanged` watcher |
#### FileChanged
Triggered when a watched file changes.
**matcher field:** Basename of the changed file (supports exact match, `|` multi-value, regex)
**Additional input fields:**
```json
{
"file_path": "/abs/path/file.ts",
"event": "change"
}
```
`event` values: `change` / `add` / `unlink`.
**hookSpecificOutput:** `additionalContext`, `watchPaths` (same as CwdChanged)
### Worktree Isolation
#### WorktreeCreate
Triggered when an isolated worktree needs to be created. The hook must return the absolute path of the worktree; any non-zero exit code is treated as failure.
**Additional input fields:**
```json
{
"name": "feature-x"
}
```
**Returning the path:** write the absolute path to stdout, or place it in `hookSpecificOutput.worktreePath`.
#### WorktreeRemove
Triggered when a worktree is being removed. Notification only — failures are surfaced via stderr.
**Additional input fields:**
```json
{
"worktree_path": "/abs/path/worktree"
}
```
### MCP Interaction
#### Elicitation
Triggered when an MCP server requests user input (elicitation). The hook can auto-accept, decline, or cancel.
**matcher field:** `mcp_server_name`
**Additional input fields:**
```json
{
"mcp_server_name": "my-server",
"message": "Please confirm",
"mode": "...",
"url": "...",
"elicitation_id": "...",
"requested_schema": {}
}
```
**Blocking:** exit 2 declines the elicitation.
**hookSpecificOutput:**
| Field | Description |
| --------- | ------------------------------------- |
| `action` | `"accept"` / `"decline"` / `"cancel"` |
| `content` | Input content provided when `accept` |
#### ElicitationResult
Triggered after the user responds to an elicitation. The hook can override the response.
**matcher field:** `mcp_server_name`
**Additional input fields:**
```json
{
"mcp_server_name": "my-server",
"action": "accept",
"content": {},
"mode": "...",
"elicitation_id": "..."
}
```
**Blocking:** exit 2 rewrites action to `decline`.
**hookSpecificOutput:** `action`, `content` (override the response)
## Practical Examples
### Desktop Notifications
Pop up a desktop notification when the Agent needs authorization or sends a notification.
Script `~/.qoder/hooks/notify.sh` (macOS):
```bash
#!/bin/bash
input=$(cat)
ntype=$(echo "$input" | jq -r '.notification_type')
if [ "$ntype" = "permission_prompt" ]; then
osascript -e 'display notification "Authorization required" with title "Qoder CLI"'
else
osascript -e 'display notification "New notification" with title "Qoder CLI"'
fi
exit 0
```
Configuration:
```json
{
"hooks": {
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "~/.qoder/hooks/notify.sh"
}
]
}
]
}
}
```
### Auto-Lint After Writing Files
Run lint checks automatically every time the Agent writes or edits a file.
Script `${project}/.qoder/hooks/auto-lint.sh`:
```bash
#!/bin/bash
input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path')
case "$file_path" in
*.js|*.ts|*.jsx|*.tsx)
npx eslint "$file_path" --fix 2>/dev/null
;;
esac
exit 0
```
Configuration: event `PostToolUse`, matcher `Write|Edit`, command `.qoder/hooks/auto-lint.sh`.
### Keep the Agent Working
When the Agent stops, check whether there are unfinished tasks; if so, inject a message to keep the Agent working.
Script `~/.qoder/hooks/check-continue.sh`:
```bash
#!/bin/bash
if [ -n "$(git status --porcelain 2>/dev/null)" ]; then
echo "Uncommitted changes detected, please complete git commit" >&2
exit 2
fi
exit 0
```
Configuration: event `Stop`, command `~/.qoder/hooks/check-continue.sh`.
# Commands
> Quickly control Qoder CLI behavior, invoke features, and manage sessions via slash commands
Control the behavior of Qoder CLI and quickly invoke specific tasks using slash commands (also known as Commands).
Commands are shortcuts in Qoder CLI for invoking specific tasks, triggered by a slash prefix (`/`). In TUI mode, type `/` to view the list of available commands and select one to execute.
## Quick Start
### Using Commands in TUI Mode
1. Launch Qoder CLI to enter TUI mode:
```bash
qoder
```
2. Type the `/` character in the input box to view the list of available commands.
3. Select the target command and press Enter to execute it. For example, use /config to view or modify Qoder CLI configuration items:
```bash
/config
```
### Using Commands in Headless Mode
Headless mode supports the execution of commands that submit prompts. Commands that require opening interactive selectors or dialogs should be used in TUI mode.
```bash
# Execute command (with additional instructions)
qoder -p '/review Focus on checking comment coverage'
# Execute custom prompt command
qoder -p '/git-commit'
```
## Command Types
Commands in Qoder CLI are divided into two types:
| Type | Description | Applicable Mode | Extensibility |
| --------------- | ---------------------------------------------------------------------------------------- | --------------- | ----------------------------------------- |
| **TUI Type** | Provides an interactive interface (e.g., pop-up dialogs, list selections) | TUI | Built-in, custom extensions not supported |
| **Prompt Type** | Submits preset prompts to the conversation to guide the CLI in completing specific tasks | TUI + Headless | Supports user-defined custom extensions |
## Built-in Commands
The table below lists common built-in commands; **for the complete list of commands, categories, and aliases, refer to the [Slash Commands Reference](/cli/slash-reference)**.
| Command | Type | Purpose |
| ----------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------- |
| `/agents` | TUI | View and manage the Subagent list, supporting the creation and editing of Subagent configurations |
| `/tasks` | TUI | View and manage background tasks |
| `/workflows` | TUI | Open the Dynamic workflows task panel. See [Dynamic workflows](/cli/built-ins) |
| `/clear` | TUI | Clear the current conversation and start a new one |
| `/commands` | TUI | View the list of available commands, browsable by categories such as Built-in, Dynamic, Skill, Plugin, and Workflow |
| `/compact` | Prompt | Compact conversation history, with the option to specify focus areas |
| `/settings` (alias `/config`) | TUI | Configuration management: view or modify Qoder CLI configuration items |
| `/export [filename]` | TUI | Export the current session to a file |
| `/feedback` | TUI | Submit feedback or report issues |
| `/help` | TUI | Display help information |
| `/init` | TUI | Initialize the project, analyze the project structure, and generate the `AGENTS.md` Memory File |
| `/login` | TUI | Sign in to your Qoder CLI account |
| `/logout` | TUI | Sign out of your Qoder CLI account |
| `/mcp` | TUI | MCP Servers management |
| `/memory` | TUI | Open the Memory Overview; when Auto-Memory is enabled, open the auto-memory folder, or use `/memory manage` to manage topic files |
| `/model` | TUI | View and manage Model-Level Settings |
| `/effort [level]` | TUI | Set the thinking depth of the current model; opens the Model Parameters Panel if no level is provided |
| `/context-window` | TUI | Set the context window of the current model; opens the Model Parameters Panel if no arguments are provided |
| `/fast [on\ | off]` | TUI | Toggle the quick mode of the current model; opens the Model Parameters Panel if no arguments are provided |
| `/quest` | Prompt | Intelligent workflow orchestrator where multiple agents collaborate to assist users in feature development |
| `/quit` | TUI | Exit Qoder CLI |
| `/release-notes` | TUI | View Release Notes |
| `/resume` | TUI | Restore previous sessions or conversation history, supporting Tab key pagination to switch sessions |
| `/review` | Prompt | Perform code review to check code quality and compliance |
| `/setup-github` | TUI | GitHub integration configuration: set up GitHub-related features |
| `/skills` | TUI | Manage Skill commands for the current workspace |
| `/status` | TUI | View current session status and system information |
| `/upgrade` | TUI | Upgrade subscription plan |
| `/usage` | TUI | View usage statistics, including token consumption and other information |
| `/vim` | TUI | Enable or configure Vim mode for a Vim-style editing experience |
## Creating Custom Commands
Qoder CLI supports creating custom commands of the Prompt type, allowing you to define the command's name, description, and system prompt via configuration files.
### Method 1: Let Qoder Generate (Recommended)
Simply describe the command you want directly in the conversation, and let Qoder generate it in the configuration file format and write it to the corresponding directory. For example:
```
> Help me create a custom command: view all git changes and generate a conventional commit message, and save it as a project-level command
```
Once generated, you can find and edit the configuration file in the following directory:
```
# Project-level
.qoder/commands/
# User-level
~/.qoder/commands/
```
The `/commands` panel is used to view the list of currently available commands by category (Built-in, Dynamic, Skill, Plugin, Workflow, etc.) and does not provide an entry point for creation.
### Method 2: Manually Write Configuration
Directly write the command configuration file in Markdown format to have full control over the command's prompt content.
#### Configuration File Format
The command configuration file is in Markdown format, containing frontmatter metadata and the system prompt:
```markdown
---
name: command-name
description: Description of the command's purpose, to be displayed in the TUI command list
---
This is the system prompt content for the command.
When the user executes this command, this prompt is submitted to the conversation to guide the CLI in completing specific tasks.
Multi-line text can be used, and Markdown formatting is supported.
```
**Field Descriptions**:
| Field | Required | Description |
| ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `name` | No | The display name of the command in the TUI; the invocation name is determined by the file path and is not affected by this field |
| `description` | Yes | The functional description of the command, supporting multiline text (using YAML syntax) |
**Naming Conventions**:
- Use lowercase letters and hyphens (e.g., `git-commit`)
- Avoid using spaces or special characters
- It is recommended to keep the filename consistent with the `name` field
- Commands in subdirectories use `:` as the namespace separator; for example, `commands/git/commit.md` is registered as `/git:commit`
- `frontmatter.name` serves only as the display name in the TUI; the command invocation name is always derived from the file path
- If `SKILL.md` exists in the same directory, the directory will be registered as a single command (e.g., `/git`), and other sibling `.md` files within the directory will be ignored
- Command name segments are preserved as-is without character replacement; it is recommended to stick to easily typable characters in filenames
#### Configuration Example
Below is an example of a command configuration used to generate Git commit messages:
```markdown
---
name: git-commit
description: Use this command when you need to review all git changes in the current repository and generate a well-structured commit message. This is particularly useful before committing code changes, especially after completing a feature or fixing a bug.
---
You are an expert Git commit message generator. Your role is to analyze all git changes in the repository and create clear, concise, and meaningful commit messages that follow conventional commit standards.
When analyzing changes, you will:
1. Examine all staged and unstaged changes using `git diff` and related commands
2. Identify the type of changes (feat, fix, chore, docs, style, refactor, test, etc.)
3. Determine the scope of changes (which component/module was affected)
4. Summarize the primary change in a clear subject line (50 characters or less)
5. Provide a detailed body explanation if the changes are complex
6. Follow conventional commit format: `(): `
Your commit message structure should be:
- Subject line: Brief summary starting with change type
- Blank line
- Body (if needed): Detailed explanation of what changed and why
- Wrap lines at 72 characters
Best practices you follow:
- Use imperative mood ("add" not "added")
- Be specific about what was changed
- Reference issue numbers when relevant
- Keep subject line under 50 characters
- Explain the 'why' behind significant changes
- Group related changes logically
If you encounter unclear changes or need more context, ask clarifying questions. If there are no changes, inform the user accordingly. Always verify your analysis covers all modifications before generating the final commit message.
```
### Storage Locations and Priority
Command configuration files can be stored in project-level or User-Level directories:
| Level | Path | Scope | Commit to Code Repository |
| ----------------- | ------------------------------------- | -------------------- | -------------------------------------- |
| **Project-Level** | `.qoder/commands/.md` | Current project only | Recommended (team sharing) |
| **User-Level** | `~/.qoder/commands/.md` | All projects | Do not commit (personal configuration) |
**Priority**: If a command with the same name exists at both the project-level and User-Level, the **User-Level** (`~/.qoder/commands/`) command takes precedence and overrides the project-level command with the same name; the overridden definitions are listed under Also defined at in the command details.
If Qoder CLI is already running, after adding or modifying a command configuration file, run `/commands` to reload and view the available commands.
## Viewing and Using Custom Commands
### Viewing the Command List
1. Execute `/commands` in the TUI to open the commands panel.
2. Use the Tab key to switch between category tabs (Built-in, Dynamic, Skill, Plugin, Workflow, etc.; only categories with commands are displayed, and the tabs indicate the count).
3. Use the up and down arrow keys to browse; the list displays the name and description of each command. Custom commands are categorized under **Dynamic**.
4. Press the Esc key to exit the panel.
The panel is for browsing only. To view the full system prompt of a specific custom command, directly open the corresponding configuration file (the `.md` file under `.qoder/commands/` or `~/.qoder/commands/`).
### Executing Commands
Type the command name (starting with `/`) in the TUI input box, and the CLI will automatically display a list of matching commands:
```
╭───────────────────────────────────────────────────────╮
│ > /git-commit │
╰───────────────────────────────────────────────────────╯
/git-commit [user] Use this command when you need to review all git changes ...
```
Press Enter to send the command, and the CLI will start executing the task according to the system prompt in the command configuration:
```
> /git-commit
● I'll help you create a commit message by analyzing the git changes in your repository.
Let me first check the current status.
● Bash (git status)
...
```
## FAQ
### Custom Commands Not Recognized
**Issue**: Created custom commands do not appear or execute in the TUI.
**Solution**:
1. Check if the configuration file path is correct (`~/.qoder/commands/` or `.qoder/commands/`).
2. Check if the frontmatter format is correct (starts and ends with `---`).
3. Run `/commands` to reload the command list. If it is still not recognized, restart the CLI (exit using `/quit` and rerun `qoder`).
### Frontmatter Parsing Failed
**Issue**: The YAML format of the command configuration is incorrect.
**Solution**:
- Ensure the frontmatter starts and ends with `---`.
- Use `|` syntax to define multiline `description` fields.
- Check if the indentation is correct (YAML is sensitive to indentation).
```yaml
---
name: my-command
description: |
This is the first line of the description
This is the second line of the description
---
```
# Built-in Capabilities Overview
> Overview of built-in slash commands, Subagents, Skills, and Workflows in Qoder CLI
Qoder CLI comes with a comprehensive set of out-of-the-box capabilities upon installation, requiring no additional configuration to use. These built-in capabilities fall into four categories:
- **Slash commands**: Commands entered in the interactive interface starting with `/`, used to manage sessions, configurations, extensions, and workflows.
- **Built-in Subagents**: Dedicated subagents pre-configured in Qoder CLI, responsible for specific tasks such as code exploration, planning, memory management, status bar configuration, and usage Q\&A.
- **Built-in Skills**: Pre-configured reusable skills that encapsulate common workflows (code review, debugging, security review, loop execution, etc.) into directly callable capabilities.
- **Workflows**: Orchestrate multi-step tasks into repeatable processes.
This page provides an overview and navigation for these four categories. For detailed parameters, aliases, scopes, and other specifics, see [Built-in Agent and Skills Reference](/cli/builtins-reference) and [Slash Commands Reference](/cli/slash-reference).
## Built-in Slash Commands
In the interactive interface, typing `/` brings up the command list with fuzzy matching support. Slash commands allow you to directly execute management and auxiliary operations within a session without leaving the current conversation. They are broadly grouped by purpose as follows.
### Session Management
| Command | Purpose |
| ----------- | ------------------------------------------------------------------------------------- |
| `/new` | Create a new empty session. |
| `/clear` | Clear the screen and conversation history to start a new session (similar to `/new`). |
| `/continue` | Resume the previous session. |
| `/resume` | Select and restore a session from the historical session list. |
| `/rename` | Rename the current session. |
| `/rewind` | Roll back to a previous checkpoint to restore code or conversation state. |
| `/export` | Export the current session content. |
| `/compact` | Compact the current conversation context to free up space in the context window. |
| `/quit` | Exit Qoder CLI. |
For complete details on session management, see [Session Management](/cli/sessions) and [Rewind Changes and Restore Sessions](/cli/undo-restore).
### Configuration and Account
| Command | Purpose |
| -------------- | ---------------------------------------------------------------------------- |
| `/login` | Sign in and complete authentication. |
| `/logout` | Sign out of the current account. |
| `/model` | Select or switch models. |
| `/theme` | Switch the UI Theme. |
| `/editor` | Configure the external editor. |
| `/settings` | View and adjust settings. |
| `/init` | Initialize project configuration (generate project instructions file, etc.). |
| `/profile` | View User Profile. |
| `/privacy` | View and adjust privacy settings. |
| `/permissions` | Manage permissions (view and adjust permission rules). |
| `/vim` | Toggle Vim edit mode. |
| `/voice` | Enable Voice Input. |
| `/statusline` | Configure Custom Status Bar. |
For configuration hierarchy and application order, see [Configuration Files and Application Order](/cli/settings).
### Extensions and Tools
| Command | Purpose |
| -------------- | -------------------------------------- |
| `/agents` | Manage Subagents (create, edit, view). |
| `/skills` | Manage Skills. |
| `/mcp` | Manage configured MCP Servers. |
| `/hooks` | Manage Hooks. |
| `/plugins` | Manage plugins. |
| `/marketplace` | Browse and install extensions. |
| `/tools` | View available Built-in Tools. |
For detailed usage of each extension mechanism, see [Subagent](/cli/builtins-reference), [Skills](/cli/builtins-reference), [MCP](/cli/mcp-reference), [Hooks](/cli/hooks-reference), and [Plugins](/cli/plugins-reference).
### Workflows and Tasks
| Command | Purpose |
| ------------ | ------------------------------------------- |
| `/plan` | Enter Plan mode (plan first, then execute). |
| `/tasks` | Manage Tasks. |
| `/workflows` | Manage Workflows. |
| `/kanban` | View tasks in Kanban View. |
| `/review` | Review Changes. |
| `/diff` | View diffs. |
### Information and Usage
| Command | Purpose |
| ---------------- | --------------------------------- |
| `/help` | View help. |
| `/docs` | Open documentation. |
| `/shortcuts` | View keyboard shortcuts. |
| `/usage` | View Usage and Quotas. |
| `/insights` | View sessions and Usage Insights. |
| `/status` | View current status. |
| `/context` | View context composition. |
| `/release-notes` | View Release Notes. |
| `/feedback` | Submit feedback. |
| `/about` | About Qoder CLI. |
## Command Availability
Some built-in commands are dynamically shown or hidden based on the current environment and settings:
- **Dependent on Feature Flags**: Commands such as Subagent, Plan mode, Skills, Workflows, and extension marketplace only appear when the corresponding capabilities are enabled.
- **Disabled by Settings**: For example, when MCP is disabled via settings, `/mcp` will prompt "MCP has been disabled by settings"; when Skills are turned off by a Management Policy, `/skills` will prompt that they are disabled.
- **Version Differences**: Some commands are only available in specific Release Versions or on specific platforms.
- **Debug Only**: Some commands are only visible in development or Debug Mode and do not appear during normal usage.
If you do not see a certain command, it usually means the corresponding capability is not yet enabled or has been turned off via settings. For the complete list, aliases, and scopes of slash commands, see [Slash Commands Reference](/cli/slash-reference).
## Built-in Subagents
Subagents are specialized agents with independent context, dedicated prompts, and toolsets. Qoder CLI comes with several built-in Subagents pre-configured, covering scenarios such as exploration, planning, memory management, and Q\&A. They are automatically delegated by the main session when needed, and can also be explicitly specified in supported scenarios.
| Subagent | Purpose | Characteristics |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **general-purpose** | A general-purpose research subagent, suitable for complex searches, multi-file analysis, call chain tracing, and multi-step tasks. | Default subagent, can use all tools (except main session-specific tools). |
| **Explore** | Fast read-only code exploration: find files by pattern, search keywords, and understand existing implementations. | Read-only, disables write and state-changing tools; the thoroughness of exploration (quick / medium / very thorough) can be specified when called. |
| **Plan** | Read-only plan design: sort out implementation paths, key files, dependency order, and architectural trade-offs. | Read-only, outputs a step-by-step implementation plan and lists key files. |
| **memory-manager** | Manages cross-session memory, preferences, and facts, maintaining personal-level and project-level instructions files. | Only available when the memory management capability is enabled; only reads and writes memory files. |
| **statusline-setup** | Configures Custom Status Bar: reads Shell configuration, generates scripts, and updates settings. | Only available in the interactive interface. |
| **qoder-guide** | Answers questions about Qoder CLI usage, configuration, Skills, Subagents, MCP, and Hooks. | Prioritizes answering based on official documentation; only available in the interactive interface. |
Built-in Subagents can be used without manual creation. You can also create your own Subagents based on these; see [Subagent](/cli/builtins-reference). For details on the toolsets, models, and invocation methods of each built-in Subagent, see [Built-in Agent and Skills Reference](/cli/builtins-reference).
## Built-in Skills
Skills encapsulate common workflows into reusable capabilities. Built-in Skills are provided with Qoder CLI and can be invoked directly as slash commands (e.g., `/simplify`). Some are also automatically triggered by the model in appropriate scenarios.
| Skill | Purpose |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/simplify` | Reviews changed code for reusability, quality, and efficiency issues, and launches multiple review perspectives in parallel to fix discovered issues. |
| `/debug` | Enables debug logs for the current session, reads the tail of the log, and assists in diagnosing issues. |
| `/security-scan` | Executes a Qoder cloud security scan on the entire repository or specified paths, supporting L2 Lightweight and L3 Deep Review. |
| `/quest` | An intelligent workflow orchestrator that guides you through feature development step-by-step using dedicated subagents. |
| `/mcp-config` | Interactively adds, updates, or removes MCP Server configurations. |
| `/loop` | Repeatedly runs a prompt or slash command at fixed intervals. |
| `/run` | Starts and drives the project's actual application to observe the effects of changes at runtime. |
| `/verify` | Verifies whether code changes achieve the expected results by running the application and observing its behavior. |
| `/remember` | Reviews Auto-Memory entries, suggests promotions to instructions files, and identifies outdated, conflicting, and duplicate entries. |
| `/batch` | Applies bulk changes across multiple files by generating parallel working agents in isolated git worktrees. |
| `/run-skill-generator` | Generates a project-level skill for the project's run and debug steps. |
### Trigger Methods
Built-in Skills have two trigger methods:
- **Manual Invocation**: Enter the corresponding slash command in the interactive interface (e.g., `/security-scan`).
- **Automatic Trigger**: Some Skills are automatically used when the model deems it appropriate. Conversely, Skills marked as not automatically triggered, such as `/debug`, `/security-scan`, and `/batch`, are only executed when explicitly called.
### Conditional Enablement
Some built-in Skills depend on specific prerequisites:
- `/batch` requires the worktree isolation capability to be enabled (and the current directory must be a Git repository).
- `/remember` requires the Auto-Memory capability to be enabled.
When prerequisites are not met, these Skills will not appear in the available list. For complete parameters and behaviors of built-in Skills, see [Built-in Agent and Skills Reference](/cli/builtins-reference); to learn how to write your own Skills, see [Skills](/cli/builtins-reference).
## Workflows
Workflows orchestrate a series of steps into repeatable processes, making them ideal for standardizing recurring multi-step tasks within a team. You can use `/workflows` to manage workflows, and `/tasks` and `/kanban` to track task progress. For detailed usage of workflows, see [Workflows](/cli/built-ins).
## How to Choose
- Need to perform one-off management or auxiliary operations in a session → Use **slash commands**.
- Need to delegate a category of tasks requiring independent context and dedicated standards to a focused executor → Use **Subagents**.
- Need to reuse a mature workflow (code review, debugging, security review, loop execution, etc.) → Use **Skills**.
- Need to standardize multi-step tasks into repeatable processes → Use **Workflows**.
## Next Steps
- Consult command details: [Slash Commands Reference](/cli/slash-reference), [Built-in Agent and Skills Reference](/cli/builtins-reference).
- Extend capabilities: [Subagent](/cli/builtins-reference), [Skills](/cli/builtins-reference), [Plugins](/cli/plugins-reference).
- Integrate team knowledge: [Knowledge Base](/cli/knowledge-base).
# Memory
> Static memory (AGENTS.md) and Auto-Memory mechanisms in Qoder CLI, including file locations and management
Qoder CLI reconstructs the context for every session. Knowledge that needs to be retained across sessions primarily comes from two types of memory:
- Static memory: Persistent instructions maintained by you or your team, including `AGENTS.md` and rules. It is suitable for development standards, project structure, common commands, and collaboration conventions.
- Auto-Memory: Markdown memory saved locally by Qoder CLI when enabled. It is suitable for recording preferences, feedback, project background, and external references that remain useful in subsequent sessions.
Memory is provided to the model as context, but it is not a strict enforcement policy. When you need to strictly block certain commands, tools, or paths, use permission configuration or Hooks.
## Memory Types
| Mechanism | Author | Suitable Content | Scope | Access Point |
| ------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| Static memory | User or team | Clear, stable instructions expected to be followed in every session; `AGENTS.md` for overall instructions, rules split by topic or file scope | User-Level, project-level, local project level, provided by plugins | `/memory` |
| Auto-Memory | Qoder CLI | Reusable information learned from conversations, such as preferences, feedback, project background, and external resource locations | project-level; optionally User-Level | `/memory` to open the auto-memory folder; `/memory manage` to manage topic files |
## Static Memory
Static memory is explicitly written and maintained by you or your team. `AGENTS.md` is suitable for hosting overall project instructions and stable conventions, while rules are ideal for splitting similar instructions into multiple Markdown files by topic or file scope.
### Static Memory Files
`AGENTS.md` is the default context file name for Qoder CLI, and rules are Markdown Rule Files placed in the `rules/` directory. When starting or refreshing memory, Qoder CLI reads the available static memory files and injects the matching content into the session as context.
#### Common Locations
```text
~/.qoder/AGENTS.md
/AGENTS.md
/AGENTS.local.md
/.qoder/rules/**/*.md
```
| Location | Purpose | Suitable to Commit |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------ |
| `~/.qoder/AGENTS.md` | Cross-project general preferences and working habits for the current user | No |
| `/AGENTS.md` | Team-shared project rules, architecture instructions, and common commands | Yes |
| `/AGENTS.local.md` | Project-private instructions on the current machine, such as local service addresses or personal test data | No |
| `/.qoder/rules/**/*.md` | Project rules split by topic or file scope | Yes |
If you need to use other file names, you can set a single file name or an array of file names via `context.fileName`. The default value is `AGENTS.md`.
#### Loading Logic
When starting or refreshing memory, Qoder CLI searches upwards for project memory and checks the project rules directory at each level:
- User-Level Memory: Loads `AGENTS.md` from the User Configuration Directory.
- Project and local project level memory: Within a Trusted Workspace, searches upwards from the current Workspace directory for `AGENTS.md`, `AGENTS.local.md`, and `.qoder/rules/**/*.md`, stopping by default at the directory containing `.git`.
- The frontmatter of rules determines the loading behavior: rules that always take effect are loaded along with the project memory; rules that apply to specific files are loaded on demand only after Qoder CLI accesses a matching file; manual rules and model-decision rules do not have their body injected at startup.
- Subdirectory memory: Not preloaded at startup. Only after Qoder CLI successfully reads a file in a subdirectory will it search upwards from that file's directory to supplement any previously unloaded `AGENTS.md`, `AGENTS.local.md`, or matching `.qoder/rules/**/*.md`. This on-demand loaded content enters the subsequent context and is displayed in `/memory`.
For example, when starting in `/repo/packages/app`, it checks:
```text
/repo/packages/app/AGENTS.md
/repo/packages/app/.qoder/rules/*.md
/repo/packages/AGENTS.md
/repo/packages/.qoder/rules/*.md
/repo/AGENTS.md
/repo/.qoder/rules/*.md
```
If started from `/repo`, `/repo/packages/app/AGENTS.md` or `/repo/packages/app/.qoder/rules/*.md` will not be preloaded; they are loaded on demand only after accessing files under `packages/app`.
### Rules
Rules are instruction files placed in the `rules/` directory and split by topic, used to replace a single bloated `AGENTS.md`. They can be split by topic (testing, API, security) or by the code areas they govern. Each rule is a standard Markdown file; the optional frontmatter determines when it takes effect.
The rules frontmatter in Qoder CLI is compatible with the rules settings configured in Qoder Desktop; rule files synced or copied from Qoder Desktop can continue to use their original trigger configurations.
#### Storage Locations
Rules have two scopes:
| Scope | Location | Effective Range | Suitable to Commit |
| ------------- | -------------------------------- | ----------------------------------------------------------- | ------------------ |
| project-level | `/.qoder/rules/**/*.md` | The project where the file is located, shared with the team | Yes |
| User-Level | `~/.qoder/rules/**/*.md` | Every project you open, for local personal use only | No |
project-level rules can be located at any level of the Workspace (including nested subdirectories) and are discovered by searching upwards from the working directory. User-Level rules are read from the User Configuration Directory and apply to all projects.
#### Supported Activation Methods
Qoder CLI supports four activation methods for rules. When no loading-related frontmatter is configured, rules are always active by default; `trigger` takes precedence over `alwaysApply` when present.
| Activation Method | Suitable Scenario | Configuration Method | Loading Behavior |
| ----------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| Always active | General rules to be followed in every session | Omit loading frontmatter, or set `trigger: always_on`, or set `alwaysApply: true` | Loads the rule body when starting or refreshing memory. |
| Manual inclusion | Occasionally used rules that require explicit inclusion | `trigger: manual` or `alwaysApply: false` | Does not automatically inject the rule body. |
| Model decision | Rules where a single description can determine relevance to the current task | `trigger: model_decision` + non-empty `description` | Injects only the rule path and description; the model reads the rule body if it determines relevance. |
| Specific files | Rules that apply only to certain files or directories | `trigger: glob` + `glob`, or directly configure `paths` | Loads the rule body on demand after Qoder CLI accesses a matching file. |
`trigger: model_decision` must be set with a non-empty `description`; `trigger: glob` must be set with a valid `glob`. If required fields are missing, the rule body will not be automatically injected into the context.
#### Configuration Examples
Rules that are always active can omit the frontmatter or be explicitly configured:
```markdown
---
trigger: always_on
---
# General Project Conventions
- Run tests before committing.
- Update documentation when modifying public APIs.
```
Rules for manual inclusion are not automatically injected into the context:
```markdown
---
trigger: manual
---
# Release Checklist
- Confirm the version number has been updated.
- Confirm the changelog has been updated.
```
Model decision rules require a `description` to determine whether to read the rule body:
```markdown
---
trigger: model_decision
description: Use when modifying API handlers, schemas, or API error structures.
---
# API Rules
- Use shared schemas under `src/api/schema/` to validate request bodies.
- Each handler must return a standard error structure.
```
When applying to specific files, you can use `trigger: glob` + `glob`:
```markdown
---
trigger: glob
glob:
- src/api/**
- "**/*.test.ts"
---
# API Rules
- Use shared schemas under `src/api/schema/` to validate request bodies.
- Every handler must return a standard error structure.
```
You can also directly use `paths` to configure path-based activation:
```markdown
---
paths:
- src/api/**
- "**/*.test.ts"
---
```
#### Configurable Frontmatter Options
| Option | Available Values | Description |
| ------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `trigger` | `always_on`, `manual`, `model_decision`, `glob` | Activation method. `always_on` means always active; `manual` means manual inclusion; `model_decision` means model decision and must be set with a non-empty `description`; `glob` means specific files and must be set with a valid `glob`. |
| `alwaysApply` | `true`, `false` | Compatibility configuration. `true` is equivalent to `trigger: always_on`; `false` is equivalent to `trigger: manual`. |
| `description` | String | Description for model decision rules, helping the model determine whether to read the rule body. |
| `glob` | Single glob or list of globs | Used with `trigger: glob` to specify the file scope where the rule applies. |
| `paths` | Single glob or list of globs | Specifies the file scope where the rule applies, behaving equivalently to `trigger: glob` + `glob`. |
Regarding `glob` and `paths`:
- Both accept a set of glob patterns. For project-level rules, globs are matched relative to the project directory containing the `.qoder/` directory; for User-Level rules, globs are matched relative to the current project root directory.
- Both are internal routing metadata: they only determine when a rule takes effect and are not injected into the model context along with the rule body.
Patterns use gitignore-style matching. Common examples:
| Pattern | Matches |
| ---------------------- | --------------------------------------------------------- |
| `**/*.ts` | All TypeScript files in any directory |
| `src/**/*` | All files at any depth under `src/` |
| `*.md` | Markdown files in any directory |
| `/*.md` | Markdown files only in the project root directory |
| `src/components/*.tsx` | Files directly under `src/components/` (excluding nested) |
#### Updating Rules During a Session
Once a rule is loaded, Qoder CLI continuously monitors the file for the remainder of the session. Edits to rules (regardless of how they were loaded, or whether they are project-level or User-Level) are detected in the next turn, allowing you to adjust rules on the fly and have Qoder CLI follow the new version without restarting. Path-based rules are also added to the monitoring list when they first match an accessed file.
### Writing Recommendations
Treat `AGENTS.md` as "facts and conventions to know for the next session." Suitable content includes:
- Build, test, formatting, and release commands
- Project directory structure and key module boundaries
- Code style, naming conventions, and review requirements
- Team-agreed workflows, such as commits, branching, and test data preparation
- Long-term security or compliance considerations for the current repository
Unsuitable content includes:
- Temporary states useful only for the current task
- Schedules and progress that will quickly expire
- Lengthy repetitive content already evident from the code or README
- Security policies that must be strictly enforced. Such requirements should be placed in permission configuration or Hooks
The more specific and stable the instructions, the better. For example:
```markdown
# Development
- Use `pnpm test` before committing changes.
- API handlers live in `src/api/handlers/`.
- Do not modify generated files under `src/generated/`.
```
### Importing Other Files
`AGENTS.md` can use `@path/to/file` to import other files. Relative paths are resolved based on the directory containing the current `AGENTS.md`.
```markdown
# Project Notes
See @README.md for the high-level architecture.
Use @docs/testing.md for test data setup.
```
Import rules:
- Supports relative paths, absolute paths, and `~/` paths.
- `@...` inside Markdown inline code and code blocks are not treated as imports.
- Project and local project level memory only allow importing files within the project boundaries by default; imports pointing outside the project require explicit approval or allowance via security settings.
- Imports are expanded recursively with a depth limit to prevent infinite expansion from circular imports.
If you just want to mention `@README.md` in the text, write it as `` `@README.md` ``.
## Auto-Memory
When Auto-Memory is enabled, Qoder CLI saves information worth reusing across sessions as local Markdown files during conversations. It does not save every conversation snippet, but rather judges whether the content is worth remembering.
### Suitable Content to Save
Auto-Memory supports four types of content:
| Type | Purpose |
| ----------- | ------------------------------------------------------------------------------------------------------------------ |
| `user` | User roles, long-term preferences, cross-project working habits |
| `feedback` | User corrections or confirmations on working methods, e.g., "don't do this in the future" |
| `project` | Background, constraints, or decision reasons in the current project that cannot be directly inferred from the code |
| `reference` | Locations of external systems, Kanban boards, dashboards, documentation, and other resources |
Auto-Memory consists of local files and will not automatically sync to other machines when code is committed. It may also become outdated; when memory involves files, functions, configurations, or external states, Qoder CLI should verify current facts before acting upon it.
### Enabling Auto-Memory
Auto-Memory only runs in interactive sessions. Enable it using either of the following methods, then restart Qoder CLI:
- Run `/settings`, search for **Auto Memory**, and turn it on.
- Add `autoMemoryEnabled` to a `settings.json` file:
```json
{
"autoMemoryEnabled": true
}
```
For configuration file locations and scope precedence, see [Configuration Files and Application Order](/cli/settings).
You can also use an Environment Variable as a temporary or deployment-level override:
```bash
QODER_MEMORY=1 qoder
```
An explicitly configured `QODER_MEMORY` value takes precedence over `settings.json`.
If you also want to enable the cross-project User-Level Auto-Memory root directory, set the following simultaneously:
```bash
QODER_MEMORY=1 QODER_MEMORY_USER=1 qoder
```
`QODER_MEMORY_USER` only takes effect when Auto-Memory is enabled. When Auto-Memory is not enabled, `/memory` can still manage `AGENTS.md` files; `/memory manage` will prompt that Auto-Memory is unavailable.
### Auto-Memory Storage Locations
project-level Auto-Memory is saved in the Qoder configuration directory corresponding to the current project:
```text
~/.qoder/projects//memory/
```
When User-Level Auto-Memory is enabled, the following is also used:
```text
~/.qoder/memory/
```
Each Auto-Memory directory contains a `MEMORY.md` index and several topic files:
```text
memory/
├── MEMORY.md
├── user-preferences.md
├── feedback-testing.md
└── project-release-context.md
```
`MEMORY.md` serves as the index and should not contain lengthy body text. When starting, Qoder CLI reads the `MEMORY.md` of each active Auto-Memory root, reading up to the first 200 lines or about 25KB. More detailed content should be placed in separate topic files and referenced by the index.
## Viewing and Managing
In the TUI, enter:
```text
/memory
```
`/memory` opens the Memory Overview, displaying User-Level, project-level, and local project level memory files, and shows the `Open auto-memory folder` entry when Auto-Memory is enabled. Selecting this entry opens the corresponding auto-memory folder using the system file manager.
To manage Auto-Memory by topic files within the TUI:
```text
/memory manage
```
`/memory manage` opens the Auto-Memory Manager, where you can view, open, edit, or delete Auto-Memory topic files. When deleting a topic file, Qoder CLI synchronously removes the corresponding `MEMORY.md` index line.
### Making Qoder CLI Remember or Forget
You can express this directly in natural language:
```text
Remember to start a local Redis server before running the integration tests for this project.
```
Or:
```text
Forget previous memory about the old deployment script.
```
If the content is more like team rules or project instructions, it is recommended to explicitly request writing to `AGENTS.md`:
```text
Add this test convention to the project AGENTS.md.
```
## Troubleshooting
### Qoder CLI is not following `AGENTS.md`
- Run `/memory` to confirm the target file appears in the list.
- Ensure the current directory is within a Trusted Workspace; untrusted directories will not load project settings, Hooks, MCP, and `AGENTS.md`.
- Check for conflicting instructions, especially between User-Level, project-level, and local project level files.
- Check if `agentsMdExcludes` excludes the target file.
- Change vague requirements into specific, verifiable rules.
### `@` imports are not taking effect
- Confirm the path actually exists and is not written inside a Markdown code block or inline code.
- Imports from outside the project are blocked by default; you need to approve external imports or adjust security settings.
- For npm package names, general mentions, and `@word` without file characteristics, Qoder CLI will not process them as file imports.
### Auto-Memory is not appearing
- Ensure you are currently in a TUI interactive session.
- Confirm that `QODER_MEMORY=1` was set at startup.
- Run `/memory` to see if the auto-memory folder entry appears; or run `/memory manage` to check if the Auto-Memory Manager is available.
- Memory is not saved in every turn; creating 0 memory entries is a normal result when there is no information worth reusing across sessions.
### Memory content is outdated
Memory reflects the context at the time it was written. When dealing with current code, configurations, or external system states, rely on the current files and current system; if you find that memory is outdated, update or delete the corresponding memory.
# Knowledge Base
> Integrate team and project knowledge into Qoder CLI, enabling Agents to leverage existing expertise when completing tasks.
The Knowledge Base refers to the long-term knowledge about your project and team that Qoder CLI can retrieve and reuse when completing tasks. It is not temporary context within a conversation, but rather content that continuously accumulates across sessions and tasks: project conventions, architectural descriptions, module responsibilities, coding standards, and solutions to common issues.
With the Knowledge Base, the Agent doesn't need to understand the project from scratch every time. It can:
- Follow the team's established conventions and standards without requiring you to re-explain them each time.
- Quickly locate relevant modules and understand module boundaries and dependencies.
- Reuse past lessons learned and verified solutions to reduce repeated mistakes.
Qoder CLI's knowledge sources primarily consist of three layers: **project instructions and rules**, **long-term memory**, and **Structured Knowledge Modules**. This page explains their differences, how to integrate them, and how to leverage them in daily use.
## The Three Layers of Knowledge
### Project Instructions and Rules
Project instructions files (`AGENTS.md`) and rule files describe "how things should be done in this project," such as which package manager to use, directory naming conventions, test commands, and code style preferences. They are committed to the repository along with the project, shared among team members, and automatically loaded by the Agent at the start of a session.
This is the most fundamental and commonly used knowledge layer, ideal for project conventions that all contributors should follow. For detailed file locations and loading logic, see [Memory](/cli/memory).
### Long-Term Memory
Long-term memory stores preferences, facts, and habits across sessions, categorized into user-level (applies to all projects) and project-level (applies only to the current project). Unlike project instructions, memory leans more towards "accumulated experiences and preferences" and can be continuously gathered and organized during use.
Qoder CLI provides memory management capabilities to maintain this content:
- The built-in Memory Management Subagent is responsible for adding, deduplicating, and organizing memory entries, routing them to the appropriate storage locations.
- `/remember` reviews automatically accumulated memory, suggests promoting entries to project instructions or local instructions files, and identifies outdated, conflicting, and duplicate entries.
For memory hierarchy, routing rules, and management methods, see [Memory](/cli/memory).
### Structured Knowledge Modules
For larger codebases, you can organize subsystem knowledge into Structured Knowledge Modules (e.g., instruction pages split by module), describing the module's architectural design, key files, responsibility boundaries, and usage. This type of knowledge is stored as documentation within the project. The Agent can retrieve it on demand when handling related tasks, rather than cramming all the content into the context at once.
Structured Knowledge Modules are ideal for consolidating domain knowledge that "requires significant effort to figure out and will be used repeatedly," enabling both new team members and the Agent to get up to speed quickly.
## How to Integrate the Knowledge Base
### Establish a Starting Point with /init
Running `/init` in the project root directory prompts Qoder CLI to analyze the project and generate an initial project instructions file. This is the simplest starting point for integrating the Knowledge Base: start with a basic project instruction and gradually expand it.
### Document Project Conventions
Write conventions that all contributors should follow into the project instructions file (`AGENTS.md`), for example:
```markdown
# Project Conventions
- Use bun instead of npm to manage dependencies
- Use kebab-case for API route naming
- Run `bun test` before committing
- Prefer functional style
```
### Accumulate and Organize Memory
During daily use, you can have Qoder CLI remember recurring preferences and facts. Subsequently, use `/remember` to periodically review these auto-memories, promote content worth long-term retention to project instructions or local instructions files, and clean up outdated and duplicate entries.
### Consolidate Structured Knowledge
For complex subsystems, organize clearly mapped-out architectures and conventions into Structured Knowledge Modules and commit them to the project. This way, whether it's team members or the Agent later on, they can reuse this knowledge without having to re-explore.
## How the Agent Uses the Knowledge Base
When completing tasks, Qoder CLI incorporates the Knowledge Base as part of the background information:
- **Automatic Loading**: At the start of a session, project instructions and rules, along with relevant long-term memory, are loaded into the context.
- **On-Demand Retrieval**: When facing specific tasks, the Agent retrieves knowledge relevant to the current task (e.g., instructions for a specific module) rather than loading everything at once, saving context space.
- **Acting as Constraints**: Retrieved conventions and standards act as behavioral constraints, influencing the Agent's planning and code generation to ensure outputs align with the team's existing practices.
- **Continuous Updates**: After task completion, if discrepancies are found between the knowledge and the current state of the code, the corresponding knowledge content can be updated accordingly to maintain the accuracy of the Knowledge Base.
## Best Practices
- **Only Write Knowledge That Will Be Reused**: The value of the Knowledge Base lies in reuse. Include content that helps subsequent tasks be done better, faster, or more in line with team conventions, rather than one-off temporary information.
- **Keep It Concise and Accurate**: Project instructions files are loaded in every session; if they are too long, they will consume context. Move detailed content to Structured Knowledge Modules, keeping only outlines and indexes in the instructions files.
- **Define Clear Layers**: Place conventions shared by all contributors in project instructions; put personal preferences in local or user-level memory; and store in-depth knowledge of complex subsystems in Structured Knowledge Modules.
- **Maintain Regularly**: As the code evolves, promptly use `/remember` to organize memory and update instructions files to prevent outdated knowledge from misleading the Agent.
- **Avoid Conflicts and Duplication**: Do not repeat the same convention across multiple layers. When conflicts are found, keep the most recent and accurate version.
## Next Steps
- Understand the complete mechanism of memory: [Memory](/cli/memory).
- Understand how context works together: [Context](/cli/how-memory-works).
- Reuse team workflows with Skills: [Skills](/cli/builtins-reference).
# Remote Control
Remote Control lets developers stay in control of running Qoder CLI Agents even when away from the computer — use your phone or browser to make critical decisions at key moments.
Qoder CLI offers two remote control modes:
Enable remote listening in an existing CLI session to monitor and control running tasks from your phone.
Run CLI as a background daemon and dispatch new tasks from your phone at any time — no need to open a session first.
## Remote control mode (remote control of local tasks)
Best when you already have a CLI session running on your computer and need to step away while keeping an eye on things. Once enabled, task progress syncs to your phone in real time. Your local computer must remain active.
In a running qoder session, type:
```bash
/remote-control
```
On success, a QR code and URL will appear. Scan the QR code with your phone camera, or copy the URL to open in a browser.
Open the Qoder mobile app (log in with the same account). You will see the connected CLI session.
Once connected, you can:
- View the local CLI's running status in real time
- Approve or reject operations that need authorization
- Send new tasks from your phone, e.g. "Optimize the interaction on this project page"
Your local terminal executes the tasks you dispatch remotely. All output files are saved on your local computer.
In the CLI, type:
```bash
/remote-control stop
```
## Daemon mode (dispatch tasks directly from mobile)
Daemon mode is also called a Daemon session.
Best when you want to keep your computer on standby and dispatch new tasks from your phone at any time. In daemon mode, the CLI continuously receives and processes multiple tasks from the Qoder mobile app. Your local computer must remain active.
Run directly in your project directory (no need to start a qoder session first):
```bash
qoder remote-control
```
On success, a QR code and URL will appear. Scan the QR code with your phone camera, or copy the URL to open in a browser.
Tap the "+" button in the bottom-right corner of the Qoder mobile app to create a new task.
- You can send a second task without waiting for the first to finish
- Each task's status and results are displayed independently
The CLI processes tasks sequentially or in parallel. All generated files are saved on the computer running the CLI.
Press `Ctrl+C` to exit.
## FAQ
**How do I check remote control status?**
Type `/remote-control status` in the CLI to view the current remote control connection status.
**How do I access the web version?**
Visit [https://qoder.com/agents](https://qoder.com/agents) in your browser to manage your remote tasks.
# Cloud Mode
The `--remote` mode runs your Qoder CLI tasks directly on a cloud VM managed by Qoder. Your local machine doesn't need to stay on or active — the entire flow from issuing the command to producing results is hosted in the cloud, and the local terminal is just the entry point.
> Complements the existing [Remote Control](/cli/remote-control) mode.
## When to use it
- **Long-running tasks**: training, bulk refactors, large-scale code review where you can't keep the local machine occupied.
- **Offline kickoff**: write a prompt on a plane or subway, and check the results later.
- **Consistent environment**: team members share the same dependencies and toolchain — no more "works on my machine."
- **Resource isolation**: the cloud VM has its own CPU / memory / network quota, so it doesn't compete with local resources.
## Quick start
### 1. Launch a task in the cloud
Pass `--remote` directly in your terminal:
```bash
qoder --remote "review the auth middleware in src/middleware and suggest improvements"
```
If you encounter a `Cannot find package` error, the current CLI version may not have the cloud dependency fully bundled. Use the [HTTP API Quickstart](/cloud-agents/quickstart) to call the Cloud Agents API directly via curl instead.
The CLI will:
1. Create a new Cloud Session in the selected remote environment.
2. Send the task description to the cloud Agent.
3. Stream the cloud Agent's output (reasoning, tool calls, final results) back to the local terminal in real time.
4. After the task completes, print the session URL to the local terminal so you can follow up via the Web console:
```plaintext
Cloud remote session created.
Session ID: qs_01krxhzz******351vhya
Environment: Default (env_01kqs75n******6x6hmj53ds)
URL: https://qoder.com/agents/session/qs_01krxhzz******351vhya
```
Once the task is launched, closing the local terminal does not stop it — the cloud Agent keeps running. Reopen the CLI or visit the Web console next time to resume tracking.
### 2. Pick a cloud environment with /remote-env
In an existing qoder interactive session, run:
```plaintext
/remote-env
```
The CLI shows an environment picker:
```plaintext
Remote Environment
Select the default cloud environment.
❯ 1. Default
2. Sessions: test · Network: trusted
```
Your selection is written to the user-level config `~/.qoder/settings.json`:
```json
{
"remote": {
"defaultCloudEnvironmentId": "env_01kq********hmj53ds"
}
}
```
All subsequent `--remote` invocations reuse this default environment — no need to pick it every time.
## Command reference
### `qoder --remote ""`
| Item | Description |
| ----------------------------- | --------------------------------------------------------------------------------------------------------- |
| Purpose | Launch a cloud session from the CLI and run the task on a Qoder-managed VM |
| Context | Does not depend on the local working directory; all reads and writes happen in the cloud environment |
| Interrupt behavior | Pressing `Ctrl+C` locally only detaches the terminal subscription; the cloud task keeps running |
| Login required | Yes (first run triggers `qoder login`) |
| Github authorization required | You must authorize Qoder for the matching Github repo (Qoder website > Integrations > Github integration) |
**Example**:
```bash
# Basic usage
qoder --remote "summarize the latest 50 PRs in this repo"
```
### `/remote-env`
| Item | Description |
| -------------- | ------------------------------------------------------------------------------------ |
| Where it works | Only inside the qoder interactive session (type `/` and pick it) |
| Purpose | Select / switch / create a cloud execution environment as the default for `--remote` |
| Scope | User level (written to `~/.qoder/settings.json`), shared across terminals |
## FAQ
**Q: Can `--remote` mode read uncommitted local changes?**
No. `--remote` tasks run inside an isolated cloud VM and access the remote Github project that corresponds to the current environment.
**Q: Can I run multiple `--remote` tasks at once on the same machine?**
Yes. Each `--remote` invocation creates an independent cloud Session — they don't interfere with each other. You can view the task list in the [Cloud Agents Console](https://qoder.com/agents).
## Related documents
- [Remote Control Guide](./remote-control)
# Qoder Action
Qoder Action is a standard GitHub Actions component that brings the powerful capabilities of Qoder CLI into your GitHub workflow, enabling intelligent code collaboration directly within PRs and Issues. With simple configuration, you can run Qoder CLI on GitHub Actions Runners to provide your team with two core out-of-the-box capabilities: automated PR reviews and @qoder interactive collaboration.
[Visit Qoder Action Repository →](https://github.com/QoderAI/qoder-action)
## Key Features
- **Automated PR Reviews**: Every pull request automatically receives a comprehensive code review, detecting code defects, security vulnerabilities, test coverage gaps, and other issues—improving code quality before merging
- **@qoder On-Demand Assistance**: Mention @qoder in any comment to get code explanations, implementation suggestions, or direct fixes
- **Deep Project Understanding**: Respects your project's coding standards, architectural patterns, and business logic
- **Quick Setup**: Complete configuration in minutes and immediately boost team efficiency
- **Secure and Reliable**: Code runs on GitHub Runners, ensuring data security
## Quick Start
### Option 1: Quick Setup (Recommended)
Run the `/setup-github` command in qoder and follow the guided setup.
### Option 2: Manual Setup
#### 1. Install GitHub App and Get Access Token
1. Visit [Qoder Integrations](https://qoder.com/account/integrations)
2. Link your Qoder account with your GitHub account and install the qoderai GitHub App to your target repository
3. Generate a Qoder Personal Access Token
**Note**: If you previously installed qoderai, visit the [GitHub App installation list](https://github.com/settings/installations) to check if qoderai has any permission upgrade requests. If so, please grant the necessary permissions.
#### 2. Add Qoder Access Token to Repository Secrets
In your repository, go to **Settings > Secrets and variables > Actions** and add `QODER_PERSONAL_ACCESS_TOKEN` with your Qoder Personal Access Token.
#### 3. Select and Install Workflow
Visit [Qoder Action examples](https://github.com/QoderAI/qoder-action/tree/main/examples), choose a workflow that fits your needs, and copy it to your repository's `.github/workflows/` directory.
- **Code Review**: Automatically analyzes pull request code quality, test coverage, and security issues
- **Assistant**: Enables interactive conversations (@qoder) in Issues and PRs to explain code or fix problems
#### 4. Start Using
- **Code Review**: Create a new pull request and wait for Qoder's feedback
- **Assistant**: Comment `@qoder explain this code` or `@qoder fix this issue` in any Issue or PR
## Best Practices
### Customize Output Language
Specify the output language in the prompt:
```
- name: Run Qoder Code Review
uses: QoderAI/qoder-action@v0
with:
qoder_personal_access_token: ${{ secrets.QODER_PERSONAL_ACCESS_TOKEN }}
prompt: |
/review-pr
REPO:${{ github.repository }} PR_NUMBER:${{ github.event.pull_request.number }}
OUTPUT_LANGUAGE: Chinese
```
### Define Review Rules Using AGENTS.md
Create an `AGENTS.md` file in your repository root. Qoder CLI will automatically load its content as context:
```
# Project Code Review Guidelines
## Review Focus
- All database queries must use parameterized queries; string concatenation is prohibited
- API endpoints must include authorization checks
- Sensitive information (passwords, tokens) must not be hardcoded or logged
- All external input must be validated and sanitized
## Checks to Ignore
- Code duplication checks in test files (`*.test.js`, `*.spec.ts`)
- Code style issues in auto-generated files (`generated/`, `dist/`)
- Complexity warnings in mock data files
## Team Conventions
- Use async/await instead of Promise.then()
- Component names use PascalCase
- Utility functions use camelCase
- Constants use UPPER_SNAKE_CASE
```
### Skip Reviews Based on PR Size
For large PRs, you can add skip conditions to avoid excessive credit consumption:
```
steps:
- name: Check PR Size
id: check_size
run: |
# Get the number of lines added in the PR
LINES_CHANGED=$(jq .pull_request.additions < $GITHUB_EVENT_PATH)
echo "Lines changed: $LINES_CHANGED"
# Skip review if over 500 lines to control costs
if [ "$LINES_CHANGED" -gt 500 ]; then
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
- uses: QoderAI/qoder-action@v0
if: steps.check_size.outputs.skip == 'false' # Only execute if PR size is within threshold
# ... other configuration
```
**For more configuration examples,** visit the [Recipes documentation](https://github.com/QoderAI/qoder-action/blob/main/docs/recipes.md) for complete configuration examples and best practices.
## Technical Support
- **GitHub Repository**: [https://github.com/QoderAI/qoder-action](https://github.com/QoderAI/qoder-action)
- **Issue Reporting**: [https://github.com/QoderAI/qoder-action/issues](https://github.com/QoderAI/qoder-action/issues)
# ACP
## What is ACP
ACP is a protocol between clients and Agents, which can be used for CLI integration with various editors. For more details, see: [Agent Client Protocol](https://agentclientprotocol.com/overview/introduction). Qoder CLI implements this protocol standard, and through this feature, it can be integrated into any client that implements the ACP protocol.
## Features
### Running Modes
Supports two running modes:
- Default mode: equivalent to CLI's default startup mode, runs according to default permission settings
- Bypass Permissions mode: equivalent to the CLI's `--yolo` mode, skips permission checks, and automatically executes tools, etc.
### Slash Commands
Currently supported commands are listed below. Command functions are the same as their corresponding commands in CLI:
- `/init`: Performs project understanding and generates the `AGENTS.md` memory file
- `/memory`: Shows or refreshes memory information
- `/about`: Shows version information
- `/help`: Shows available ACP commands
### Other Features
| **Feature** | **Support** | **Description** |
| :-------------------------- | :---------- | :-------------------------------------------------------------------- |
| Built-in Tools | ✅ | Provides the same built-in tools as CLI |
| Subagent | ✅ | Provides the same Subagent capability as CLI |
| MCP Server | ✅ | Provides the same Stdio, SSE, Streamable HTTP type MCP support as CLI |
| Permission Configuration | ✅ | Provides the same permission configuration capability as CLI |
| Context Compression | ✅ | Provides the same context compression mechanism as CLI |
| Multimodal | ✅ | Supports images |
| File Operations or Terminal | ✅ | Uses capabilities provided by the IDE side through the ACP protocol |
## Getting Started
Before starting, please ensure that Qoder CLI is installed. For installation instructions, refer to the Qoder CLI Quick Start. Currently supported operating systems and CPU architectures are as follows:
- **Supported operating systems:** macOS, Linux, Windows
- **Supported CPU architectures:** arm64, amd64 (Windows arm64 architecture is temporarily not supported)
### Starting ACP Server
If you have ACP client development scenarios and expect to implement Agent Server through Qoder CLI, you can start the CLI directly through commands. Simply pass the `--acp` parameter when starting Qoder CLI, and the CLI will start as an ACP server. ACP clients can communicate with this server using standard input/output.
```
qoder --acp
```
### Starting in Zed IDE
Integrating Qoder CLI with Zed IDE only requires adding the following extension configuration to the Zed configuration file to add Qoder CLI support in Zed IDE. After configuration is complete, you can select Qoder CLI when creating a Thread.
- macOS / Linux platform configuration
```
{
...
"agent_servers": {
"Qoder CLI": {
"type": "custom",
"command": "qoder",
"args": ["--acp"]
}
}
}
```
- Windows platform configuration
```
{
...
"agent_servers": {
"Qoder CLI": {
"type": "custom",
"command": "~\\AppData\\Roaming\\npm\\qoder.cmd",
"args": ["--acp"]
}
}
}
```
Note: In Zed version 0.215.2 and earlier, the type does not need to be configured.
Zed IDE configuration file paths for different operating systems:
- **macOS:** \~/.config/zed/settings.json
- **Linux**: \~/.config/zed/settings.json
- **Windows**: \~\AppData\Roaming\Zed\settings.json
## Login and Usage
ACP clients use the same login state as Qoder CLI. Currently, you need to log in through Qoder CLI. If you have already logged in and used Qoder CLI, you can use the ACP client normally without logging in again.
### Log in through Qoder CLI
If you have never logged into Qoder CLI, please enter the following command in the terminal to open the login interface:
```
qoder login
```
Qoder CLI starts the browser login flow, prints the login URL, and opens it in your browser when possible. Follow the terminal instructions to complete authentication.
### Log in through Environment Variables
Qoder CLI supports detecting the `QODER_PERSONAL_ACCESS_TOKEN` environment variable to complete authentication at startup. Therefore, ACP clients can configure this environment variable to allow Qoder CLI to automatically log in. You can obtain a Personal Access Token on this page: [https://qoder.com/account/integrations](https://qoder.com/account/integrations)
Below is an example configuration for adding the Qoder Access Token environment variable in Zed IDE.
```
{
...
"agent_servers": {
"Qoder CLI": {
"env": {
"QODER_PERSONAL_ACCESS_TOKEN": "your_personal_access_token_here"
},
"command": "qoder",
"args": ["--acp"]
}
}
}
```
# Configuration Files and Application Order
> Three-tier configuration files, merge priority, and common configuration items in Qoder CLI
The behavior of Qoder CLI can be customized through JSON configuration files (`settings.json`). The configuration uses a hierarchical design: the same setting can be defined at different levels and is ultimately merged into an effective value based on a fixed precedence. Understanding this hierarchy and merging rules is fundamental to managing personal preferences and team conventions.
This page covers the locations of configuration files, merge precedence, and common configuration items. For a complete list of configuration items and environment variables, see [Configuration Item Reference](/cli/settings-reference).
## Configuration File Locations
Qoder CLI reads configuration files from three levels:
| Level | Path | Description |
| ----------------- | -------------------------------------- | ---------------------------------------------------------------------------------------- |
| **User Level** | `~/.qoder/settings.json` | Personal preferences that apply to all projects for the current user. |
| **Project-Level** | `/.qoder/settings.json` | Shared project configuration, committed to the repository and shared among team members. |
| **Local Level** | `/.qoder/settings.local.json` | Personal overrides within a project, typically not committed to the repository. |
The default configuration directory is `~/.qoder`, which can be modified via the environment variable `QODER_CONFIG_DIR`. For the complete structure of the `.qoder/` directory, see [.qoder directory](/cli/config-scope).
## Merge Precedence
When the same configuration item appears at multiple levels, Qoder CLI merges them in the following order of precedence from lowest to highest, where **higher precedence overrides lower precedence**:
1. **Built-in defaults** (Schema defaults)
2. **User Level settings** (`~/.qoder/settings.json`)
3. **Project-Level settings** (`/.qoder/settings.json`)
4. **Local Level settings** (`/.qoder/settings.local.json`)
5. **Configurations specified via command-line `--settings`** (Highest precedence)
In other words: Local Level overrides Project-Level, Project-Level overrides User Level, and configurations explicitly passed via the command line take precedence over all files.
### Merge Behavior
Configurations use deep merge rather than wholesale replacement:
- **Objects**: Recursively merged field by field; only present fields are overridden, while the rest retain lower-precedence values.
- **Single values (strings, numbers, booleans)**: Directly overridden by higher precedence.
- **Arrays**: Some configuration items (such as disable lists and exclude lists) use "union merge" to combine and deduplicate values across levels; other arrays are overridden by default.
Therefore, at the Project-Level, you only need to specify the fields you want to override, without copying the entire user configuration.
### Impact of Folder Trust
For security reasons, Project-Level and Local Level configurations are only applied when the current working directory is trusted. If the working directory is not trusted, Qoder CLI only loads User Level configurations and ignores `settings.json` and `settings.local.json` within the project. Folder Trust is controlled by `security.folderTrust.enabled` (enabled by default).
## File Format
Configuration files are in JSON format (supporting `//` comments, see below). The top level is an object, and most configuration items are nested by group, with a few items located directly at the top level (such as `outputStyle`, `language`, and `agent`). For example:
```json
{
"outputStyle": "concise",
"ui": {
"theme": "Tokyo Night",
"autoThemeSwitching": true
},
"model": {
"name": "auto",
"maxSessionTurns": -1
},
"tools": {
"useRipgrep": true
}
}
```
Notes:
- Configuration files can contain comments (ignored during parsing), making it easy to add explanations for team conventions.
- Environment variables can be referenced in values and will be resolved and replaced at runtime.
- Modifying certain configuration items requires restarting Qoder CLI to take effect (see notes below).
## Common Configuration Items
The following lists the most frequently adjusted configuration items, organized by group. Items marked with "requires restart" require a restart to take effect after modification.
### Top-Level Configuration Items
The following configuration items are written directly at the top level of the configuration file and do not belong to any group:
| Configuration Item | Type | Default | Description |
| ------------------ | ------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `outputStyle` | string | None | Name of the active Output Style (requires restart). Compatible with the `general.outputStyle` syntax, with top-level taking precedence. See [Output Style](/cli/output-styles). |
| `language` | string | None | Preferred language for AI responses (requires restart). |
| `agent` | string | None | Name of the Agent used for the main thread (requires restart). |
### ui (UI)
| Configuration Item | Type | Default | Description |
| ------------------------------- | ------- | ------- | ------------------------------------------------------------------------------------------ |
| `ui.theme` | string | None | Color Theme name. |
| `ui.autoThemeSwitching` | boolean | `true` | Automatically switch between Light and Dark Themes based on the terminal background color. |
| `ui.customThemes` | object | `{}` | Custom theme definitions. |
| `ui.hideBanner` | boolean | `false` | Hide the Startup banner. |
| `ui.showLineNumbers` | boolean | `true` | Display line numbers in conversations. |
| `ui.loadingPhrases` | enum | `off` | Content to display during loading: `tips` / `witty` / `all` / `off`. |
| `ui.accessibility.screenReader` | boolean | `false` | Screen Reader Mode, outputs plain text (requires restart). |
For more UI and Shortcuts configurations, see [UI and Shortcuts](/cli/interface).
### model (Model)
| Configuration Item | Type | Default | Description |
| ----------------------- | ------ | ------- | ------------------------------------------------------------------- |
| `model.name` | string | None | Model used for conversations. |
| `model.reasoningEffort` | enum | None | Reasoning Effort Level: `low` / `medium` / `high`, etc. |
| `model.maxSessionTurns` | number | `-1` | Maximum number of conversation turns to retain, `-1` for unlimited. |
### tools (Tools)
| Configuration Item | Type | Default | Description |
| ------------------------------- | --------------------- | ------- | --------------------------------------------------------------------------------- |
| `tools.sandbox` | string/boolean/object | None | Sandbox execution environment (requires restart). |
| `tools.sandboxAllowedPaths` | string\[] | `[]` | Additional paths accessible by the sandbox (requires restart). |
| `tools.sandboxNetworkAccess` | boolean | `false` | Whether the sandbox is allowed to access the network (requires restart). |
| `tools.useRipgrep` | boolean | `true` | Use ripgrep for content search. |
| `tools.shell.inactivityTimeout` | number | `300` | Timeout in seconds for shell commands with no output. |
| `tools.core` | string\[] | None | Allowlist for built-in tools; only listed tools are permitted (requires restart). |
| `tools.exclude` | string\[] | None | Tool names to exclude from discovery (requires restart). |
### security (Security)
| Configuration Item | Type | Default | Description |
| ----------------------------------------------- | ------- | ------- | --------------------------------------------------------------------------- |
| `security.folderTrust.enabled` | boolean | `true` | Whether to enable Folder Trust (requires restart). |
| `security.toolSandboxing` | boolean | `false` | Tool-Level Sandbox isolation (requires restart). |
| `security.disableYoloMode` | boolean | `false` | Disable the `bypass_permissions` (YOLO) permission mode (requires restart). |
| `security.blockGitExtensions` | boolean | `false` | Block installing and loading extensions from Git (requires restart). |
| `security.environmentVariableRedaction.enabled` | boolean | `false` | Mask environment variables that may contain keys (requires restart). |
### mcp (MCP Servers)
| Configuration Item | Type | Default | Description |
| ------------------ | --------- | ------- | ---------------------------------------------------------------------------- |
| `mcpServers` | object | `{}` | MCP server configurations (requires restart). See [MCP](/cli/mcp-reference). |
| `mcp.allowed` | string\[] | None | Allowlist of MCP servers (requires restart). |
| `mcp.excluded` | string\[] | None | Exclude list of MCP servers (requires restart). |
### statusLine (Status Bar)
| Configuration Item | Type | Default | Description |
| -------------------- | ------ | --------- | -------------------------------------------------------------------------------- |
| `statusLine.type` | string | `command` | Status Bar type; currently only `command` is supported. |
| `statusLine.command` | string | `""` | Shell command to generate the Status Bar, receiving session data JSON via stdin. |
| `statusLine.padding` | number | `0` | Number of horizontal padding characters for the Status Bar. |
## Editing Configurations
There are two ways to modify configurations:
- **In the Interactive interface**: Run `/settings` to open the Settings Panel to directly view and adjust common configuration items.
- **Manually editing files**: Open the `settings.json` for the corresponding level in an editor, and add or modify fields according to the tables above.
After modification, items not marked with "requires restart" usually take effect immediately; items marked with "requires restart" require restarting Qoder CLI.
## Next Steps
- View all configuration items and environment variables: [Configuration Item Reference](/cli/settings-reference).
- Add custom models through the `/model` wizard: [Custom Models](/cli/custom-models).
- Customize UI and shortcuts: [UI and Shortcuts](/cli/interface).
- Troubleshoot configuration issues: [Configuration Troubleshooting](/cli/troubleshoot-config).
# Permissions
## Permission Modes
Permission modes determine how Qoder handles tool calls — each mode balances automation and security differently.
| Mode | Best for | Behavior |
| :-------------------------- | :---------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `default` | Normal interactive use | Safe reads and internal actions run automatically; sensitive actions require confirmation. |
| `accept_edits` | Routine coding tasks | Automatically approves safe file edits inside working directories. Shell commands, external actions, and sensitive paths still go through normal checks. |
| `auto` | Autonomous runs, Goal execution | Zero prompts. Safe reads and workspace edits are auto-approved; risky actions are denied or evaluated by the AI classifier. |
| `bypass_permissions` (YOLO) | Trusted local experiments only | Skips all approval prompts. All tool calls are allowed automatically. |
| `dont_ask` | Headless flows that must not prompt | Never prompts. Any action that would normally ask is denied instead. |
### Plan Mode
Plan is an independent **work state** (not a permission policy) that can coexist with any permission mode above. Toggle it with the `/plan` command. While active, Qoder explores code in read-only mode and outputs proposals; writes are restricted to plan files. On exit you can choose a follow-up permission mode or start a Goal execution.
### Goal Mode
Goal is an autonomous execution state. Enter via `/goal set ` — this automatically switches to `auto` mode and locks Shift+Tab switching to ensure zero-interruption execution. Goal can coexist with Plan (plan first, execute second). Exit with `/goal clear` or `/goal pause`.
### Mode Cycling
In interactive sessions, press **Shift+Tab** to cycle through all permission modes. Press **Ctrl+Y** to jump directly to YOLO mode.
### Startup Parameters
Use `--permission-mode` to set the default behavior for the current session:
```shell
qoder --permission-mode default
qoder --permission-mode accept_edits
qoder --permission-mode plan # Legacy compat: translates to default + enters Plan work state
qoder --permission-mode auto
qoder --permission-mode bypass_permissions
qoder --permission-mode yolo # Equivalent to bypass_permissions
qoder --permission-mode dont_ask
# Shortcuts
qoder --yolo # Equivalent to --permission-mode bypass_permissions
qoder --dangerously-skip-permissions # Same as above
```
In interactive sessions, you can also press **Ctrl+Y** to quickly switch to YOLO mode.
Multiple naming formats are supported (case-insensitive):
| Standard (snake\_case) | camelCase | Alias |
| :--------------------- | :------------------ | :------------- |
| `accept_edits` | `acceptEdits` | — |
| `bypass_permissions` | `bypassPermissions` | `yolo`, `YOLO` |
| `dont_ask` | `dontAsk` | — |
Example:
```shell
# The following are equivalent
qoder --permission-mode bypass_permissions
qoder --permission-mode bypassPermissions
qoder --permission-mode yolo
qoder --yolo
qoder --dangerously-skip-permissions
```
Non-default modes only take effect in trusted directories. If the current directory is not trusted, Qoder falls back to `default`.
## How Decisions Are Made
Qoder checks permissions before every tool call. The result is always one of three outcomes:
- **`allow`**: Execute the tool immediately.
- **`ask`**: Requires external confirmation before execution.
- **`deny`**: Block the tool call.
Permissions apply to file reads and edits, Bash commands, web fetches, MCP tools, subagents, and other built-in tools.
### Decision Order
Qoder evaluates permissions in a fixed order:
1. Check `deny` rules first — if matched, deny immediately.
2. Tool's own safety checks (e.g., dangerous command detection, sensitive path detection).
3. `ask` rules — if matched, mark as requiring confirmation.
4. Tool-level `allow` rules and mode-based auto-allow behavior.
5. If the final result is still `ask`, the runtime environment determines how to consume it.
Broad allow rules do not mean all actions execute silently — safety checks and ask rules have higher priority.
### How `ask` Is Consumed in Different Environments
| Environment | `ask` outcome | Notes |
| :----------------------------- | :----------------------------------- | :---------------------------------------------- |
| **TUI** (interactive terminal) | Confirmation prompt | User selects allow/deny in the terminal. |
| **Headless** (`-p`/`--prompt`) | Auto-deny | No interaction available; `ask` becomes `deny`. |
| **SDK** (stdio protocol) | Sends `canUseTool` callback to host | Host program decides allow/deny. |
| **ACP** (IDE integration) | Sends `requestPermission` RPC to IDE | IDE prompts or auto-decides. |
Headless mode (`-p`/`--prompt`) can be combined with permission modes:
```shell
# Headless + accept_edits: file edits auto-approved, Bash denied
qoder -p "refactor the utils module" --permission-mode accept_edits
# Headless + bypass_permissions: all allowed (trusted scenarios only)
qoder -p "run the migration" --yolo
# Headless + precise allow rules: only specific tools allowed
qoder -p "check status" --allowed-tools 'Read,Bash(git status)'
```
## Permission Configuration
### Configuration Sources (8-Layer Priority)
Rules merge from multiple sources, from lowest to highest priority:
| Layer | Source | Description |
| :---- | :---------------- | :-------------------------------------------------------------------------- |
| 1 | `userSettings` | `~/.qoder/settings.json` (user global) |
| 2 | `projectSettings` | `/.qoder/settings.json` (project-level, team-shared) |
| 3 | `localSettings` | `/.qoder/settings.local.json` (machine-local, add to `.gitignore`) |
| 4 | `flagSettings` | `--settings ` CLI argument specifying an additional file |
| 5 | `cliArg` | `--allowed-tools` / `--disallowed-tools` CLI arguments |
| 6 | `command` | `/allow`, `/deny` in-session commands |
| 7 | `session` | Runtime temporary rules ("Allow for this session" in prompts) |
Higher-priority sources override lower ones. If organization policy enables `allowManagedPermissionRulesOnly`, only policy-managed rules are used.
**How each source is configured:**
- **Layers 1-3 (settings files)**: Write `permissions.allow` / `permissions.deny` / `permissions.ask` arrays in the corresponding JSON file. `settings.local.json` is ideal for machine-local approval rules; add it to `.gitignore`.
- **Layer 4 (flagSettings)**: `qoder --settings ./custom-settings.json` specifies an additional settings file. Same format as standard settings.json.
- **Layer 5 (cliArg)**: Configured via `--permission-mode`, `--allowed-tools`, `--disallowed-tools`, `--tools` CLI arguments; applies to current session only.
- **Layer 6 (command)**: Type `/allow Bash(npm test)` or `/deny WebFetch` in-session; persisted to `settings.local.json`.
- **Layer 7 (session)**: Temporary rules from selecting "Allow for this session" in prompts; lost when the process exits.
### Mode Configuration
**Set default mode** — configure `general.defaultPermissionMode` in settings:
```json
{
"general": {
"defaultPermissionMode": "accept_edits"
}
}
```
Supported values:
| Value | Behavior | Aliases |
| -------------------- | ------------------------------------------------------------------- | --------------------------- |
| `default` | Prompts for approval on every action | — |
| `accept_edits` | Auto-approves file edits, shell commands still require confirmation | `acceptEdits` |
| `plan` | Read-only mode (legacy compat: maps to default + Plan work state) | — |
| `auto` | AI classifier evaluates action safety | — |
| `bypass_permissions` | Skip all permission checks (YOLO) | `yolo`, `bypassPermissions` |
| `dont_ask` | Non-interactive: deny anything requiring approval | `dontAsk` |
Case-insensitive. All aliases are accepted.
**Disable YOLO mode** — organization admins can prevent users from entering bypass\_permissions mode:
```json
{
"security": {
"disableYoloMode": true
}
}
```
When set, `--yolo`, `--permission-mode bypass_permissions`, and Ctrl+Y are all disabled, and the Shift+Tab cycle skips this mode. Sub-agents declaring bypass are also downgraded to acceptEdits.
**Disable Plan mode** — if the Plan workflow is not needed:
```json
{
"general": {
"plan": {
"enabled": false
}
}
}
```
When set, the `/plan` command is unavailable, `--permission-mode plan` falls back to default, and EnterPlanMode/ExitPlanMode tools are not registered.
**Auto mode classifier configuration** — guide the AI classifier's decisions with natural language rules:
```json
{
"autoMode": {
"allow": [
"running npm/yarn/pnpm scripts defined in package.json",
"creating or editing test files"
],
"soft_deny": [
"deleting files outside the test directory",
"modifying CI/CD configuration"
],
"environment": [
"This is a Node.js monorepo with pnpm workspaces",
"The project uses Vitest for testing"
]
}
}
```
| Field | Purpose |
| :------------ | :---------------------------------------------------------- |
| `allow` | Operation descriptions the classifier tends to auto-approve |
| `soft_deny` | Operation descriptions the classifier tends to deny |
| `environment` | Environment context provided to the classifier |
These rules are **soft guidance** — injected into the classifier prompt as reference; the final decision is still made by the AI classifier. For security, `autoMode` configuration is only read from trusted sources (user global settings and localSettings); project settings are excluded to prevent malicious privilege escalation.
### Permission Rule Configuration
Rules are grouped under `allow`, `ask`, and `deny`:
```json
{
"permissions": {
"allow": [
"Read(/src/**)",
"Edit(/src/**)",
"Bash(npm run test:*)"
],
"ask": [
"Bash(npm publish:*)",
"WebFetch"
],
"deny": [
"Read(*.pem)",
"Bash(rm -rf:*)"
]
}
}
```
### Rule Syntax
| Form | Meaning |
| :------------------ | :----------------------------------------------------------------------------- |
| `ToolName` | Applies to the entire tool. |
| `ToolName(content)` | Applies to a specific path, command, agent type, or other tool-specific value. |
| `*` | Matches all tools. |
Use canonical tool names: `Read`, `Edit`, `Write`, `Bash`, `Grep`, `Glob`, `WebFetch`, `WebSearch`, `Agent`, and MCP names like `mcp__github__create_issue`.
If the content contains parentheses, escape them:
```json
{
"permissions": {
"allow": [
"Bash(python -c \"print\\(1\\)\")"
]
}
}
```
`ToolName(*)` is equivalent to `ToolName` (tool-level rule).
### Command-Line Overrides
```shell
qoder --allowed-tools 'Read,Grep,Bash(git status)'
qoder --disallowed-tools 'Bash(rm -rf:*),mcp__github__delete_repo'
qoder --tools 'Read,Grep,Edit'
```
`--allowed-tools` and `--disallowed-tools` use the same rule syntax as settings. `--tools` restricts the available built-in tool set for the current run (unlisted tools are denied).
## Trust Directories
Qoder treats the startup current working directory (CWD) as the **main trust directory**. Within trusted directories:
- File reads are allowed by default
- File writes can be auto-approved in `accept_edits` and `auto` modes
- Non-default permission modes (auto, bypass, etc.) are allowed to take effect
If the current directory is not trusted, Qoder forces a fallback to `default` mode.
### Extending Trust
Add additional trusted working directories via `--add-dir`, the `/add-dir` command, or `permissions.additionalDirectories`:
```shell
qoder --add-dir ../shared
```
```json
{
"permissions": {
"additionalDirectories": ["../shared"]
}
}
```
You can also configure `permissions.trustDirectories` in global settings to permanently trust frequently-used directories.
### Protected Paths
Some paths are protected because editing them can change execution behavior, credentials, or tool behavior. Examples include `.git`, `.vscode`, `.idea`, `.husky`, most `.qoder` configuration files, shell startup files like `.bashrc`/`.zshrc`, Git config, `.mcp.json`, and `.ripgreprc`. In normal interactive modes these paths require explicit approval; in `auto` mode they are denied.
## File Access Rules
Path-scoped read rules use `Read(...)`. Path-scoped write rules use `Edit(...)`; they cover file editing and writing checks for `Edit`, `Write`, and `NotebookEdit`. An `Edit(...)` allow rule also implies read permission for the same path.
File rules use gitignore-style matching.
| Pattern | Meaning |
| :--------------- | :--------------------------------------------------------------------------------------------------------------------------------------------- |
| `/src/**` | Rooted at the rule source's root directory. In project/local settings, relative to project root; in user settings, relative to home directory. |
| `~/Documents/**` | Home-directory-based path. |
| `//tmp/data/**` | Absolute path from system `/`. Use double slash for absolute paths. |
| `*.secret` | Rootless filename pattern that matches at any location. |
Examples:
```json
{
"permissions": {
"allow": [
"Read(/src/**)",
"Edit(/src/**)",
"Read(~/Documents/specs/**)"
],
"ask": [
"Edit(/package.json)",
"Read(~/Downloads/**)"
],
"deny": [
"Read(*.pem)",
"Edit(/.git/**)",
"Edit(//etc/**)"
]
}
}
```
## Bash Rules
`Bash(...)` rules can match exact commands, command prefixes, or wildcard patterns.
| Rule | Matches |
| :--------------------- | :---------------------------------------------------------- |
| `Bash(npm run build)` | Exactly `npm run build`. |
| `Bash(npm run test:*)` | `npm run test` and commands beginning with `npm run test `. |
| `Bash(git log *)` | Glob-style wildcard matching. |
| `Bash(git status)` | Exactly `git status`. |
Examples:
```json
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git log:*)",
"Bash(npm run test:*)"
],
"ask": [
"Bash(npm publish:*)",
"Bash(git push:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(sudo:*)"
]
}
}
```
Shell matching is conservative:
- `deny` and `ask` rules see through common wrappers and environment variable prefixes, so `Bash(rm -rf:*)` still catches wrapped destructive commands.
- Prefix and wildcard `allow` rules do not silently approve compound commands unless every top-level command segment is independently allowed.
- Some provably read-only shell commands can be automatically allowed after deny, ask, and path checks.
- Dangerous commands (destructive deletes, force pushes) can still force confirmation even with broad allow rules. In `auto` mode, dangerous shell commands are denied.
Avoid broad rules like `Bash` or `Bash(*)` unless you fully trust the session.
## Web and MCP Rules
Web tools can be controlled at the tool level. Use `ask` when every web fetch should require confirmation, or `deny` when web access should be blocked for a session or project.
```json
{
"permissions": {
"ask": [
"WebFetch"
],
"deny": [
"WebSearch"
]
}
}
```
MCP tools use fully qualified names:
```text
mcp____
```
Supported MCP patterns include:
| Rule | Meaning |
| :-------------------------- | :-------------------------------------- |
| `mcp__github__create_issue` | A single MCP tool. |
| `mcp__github__*` | All tools from the `github` MCP server. |
| `mcp__github` | All tools from the `github` MCP server. |
| `mcp__*` | All MCP tools. |
Example:
```json
{
"permissions": {
"allow": [
"mcp__context7__*"
],
"ask": [
"mcp__github__create_issue"
]
}
}
```
MCP server configs can also set `alwaysAllow` for tools from that server. To enable only selected MCP servers for a run, use `--allowed-mcp-server-names`.
```shell
qoder --allowed-mcp-server-names context7,github
```
## Hooks and Permissions
Qoder's Hook system has two injection points in the permission decision pipeline, allowing custom scripts to influence allow/deny behavior.
### Hook Events That Affect Permissions
| Hook Event | Trigger | Permission Impact | | |
| :------------------ | :--------------------------------------------- | :------------------------------------------------------------------------------ | ------ | ------------------------------------------------ |
| `PreToolUse` | Before tool execution (permission check phase) | Can return \`permissionDecision: "allow" | "deny" | "ask"\` to directly override the pipeline result |
| `PermissionRequest` | After pipeline produces `ask`, before prompt | Can return `decision.behavior` as `allow` or `deny` to replace user interaction | | |
Other hook events (`PostToolUse`, `SessionStart`, `Stop`, etc.) do not participate in permission decisions.
### PreToolUse Hook
Triggered before tool execution. The hook script can inspect the tool name and parameters, returning a permission decision:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python ./scripts/check-bash-command.py"
}
]
}
]
}
}
```
Hook scripts receive JSON input via stdin (containing `tool_name`, `tool_input`, `session_id`, etc.) and output JSON results via stdout:
```json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Command blocked by security policy"
}
}
```
`permissionDecision` values:
- `"allow"`: Skip permission pipeline, approve directly
- `"deny"`: Skip permission pipeline, deny directly
- `"ask"`: Continue through normal permission pipeline (default behavior)
### PermissionRequest Hook
Triggered after the permission pipeline produces `ask`, before the prompt/callback. Suitable for automated approval systems or external notifications (e.g., Slack/email alerts):
```json
{
"hooks": {
"PermissionRequest": [
{
"hooks": [
{
"type": "command",
"command": "node ./scripts/auto-approve-safe-ops.js"
}
]
}
]
}
}
```
Output format:
```json
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": {},
"updatedPermissions": []
}
}
}
```
### Hook Priority vs. Permission Modes
Hook permission decisions have **higher priority** than permission modes — even in `bypass_permissions` mode, a PreToolUse hook returning `deny` will still block execution. This provides an unbypassable interception capability for organization-level security policies.
Execution order:
1. Hook `PreToolUse` → if returns allow/deny, short-circuit
2. Permission pipeline (rules + mode + safety checks)
3. If result is `ask` → Hook `PermissionRequest` → if returns allow/deny, short-circuit
4. Finally, the runtime environment consumes `ask` (prompt/deny/callback)
# Security Scan
> Learn how to use Qoder CLI security scanning during interactive development and in CI/CD.
Qoder CLI includes built-in security scanning to help identify high-risk issues while code is generated and changed. It adds a continuous security check to everyday development, helping you catch dangerous function calls, injection risks, sensitive data leaks, and data-flow issues earlier.
Security scanning is not a replacement for a full security audit. Interactive scans focus on code generated in the current task and incremental changes. Repository scans can check the whole repository or selected paths and provide a deterministic security gate for CI/CD.
## Entry Point
In the interactive TUI, run:
```text
/security-settings
```
This opens the security scan settings panel. You can view and toggle each scan level from this panel.
Security scanning is enabled by default. Settings are saved to your user configuration and control which scan levels are active. L1 Static Check is free; L2 Lightweight Scan and L3 Deep Scan may consume Credits, depending on in-product prompts and your account's billing rules.
## Scan Levels
Qoder CLI divides security scanning into three levels. You can enable or disable each level independently.
### L1 Static Check
L1 applies to code generated in the current task. It uses high-risk pattern matching to quickly catch common issues such as dangerous function calls, obvious sensitive data leak patterns, and other risks that often appear in generated code.
L1 Static Check is a free baseline check. We recommend keeping it enabled by default so Qoder can quickly catch high-risk code patterns during the current task.
### L2 Lightweight Scan
L2 applies to incremental code changes. It understands code semantics more deeply to identify risks such as SQL injection, remote command execution, and sensitive data leaks.
Enable L2 when you want deeper security feedback during everyday coding.
### L3 Deep Scan
L3 performs deeper analysis on incremental code changes. It traces data flows across files and functions to uncover hidden vulnerabilities that may not be visible from a single-file view.
L3 is best used after commits are ready and before review, push, PR, release, or deployment handoff. If only working-tree changes exist, it may fall back to L2.
## Configure Scan Levels
After opening `/security-settings`, use the arrow keys to move between scan levels, and press Enter or Space to toggle a level. Press `q` or Esc to close the panel.
Each item in the panel shows its current state:
- `on` means the level is enabled.
- `off` means the level is disabled.
- `default` means the default value is being used.
- `saved` means the value has been written to user settings.
The settings panel writes only to user-level settings. It does not modify project-level settings.
## Use the Settings File
You can also configure security scanning in your user-level `settings.json`. The settings live under `securityScan`:
```json
{
"securityScan": {
"l1StaticCheck": true,
"l2LightweightScan": true,
"l3DeepScan": true
}
}
```
All three options default to `true`. To disable a level, set the corresponding field to `false`:
```json
{
"securityScan": {
"l1StaticCheck": true,
"l2LightweightScan": false,
"l3DeepScan": false
}
}
```
## How Automatic Scanning Works
When security scanning is enabled, Qoder CLI loads the built-in security capability according to your configuration and decides which checks to activate.
When L1 is enabled, Qoder CLI triggers static checks after relevant tool calls. When L1 is disabled, this automatic check is not loaded.
As long as at least one of L1, L2, or L3 is enabled, Qoder CLI keeps the unified security scan capability available. If all three levels are disabled, security scan capabilities are not loaded.
## Manual Security Scan
In addition to automatic scan settings, Qoder CLI provides a manual security scan Skill:
```text
/security-scan
```
The command routes security intent to one of three workflows:
- **Project/file scan**: scans the whole repository or exact files and directories that you specify.
- **L2 lightweight review**: reviews current working-tree changes.
- **L3 deep review**: reviews unreviewed committed changes before push, PR, release, deployment, or other handoff workflows.
A bare `/security-scan` opens a picker with L3 deep scan, L2 lightweight scan, and Project/file scan. If you select Project/file scan without a scope, Qoder CLI asks whether to scan the whole repository or specific files and directories.
You can also include the mode or scope directly:
```text
/security-scan L2 lightweight review
/security-scan L3 deep review
/security-scan scan the whole repository
/security-scan scan src/auth and src/export
```
Project/file scans are available when any security scan level is enabled. L2 and L3 follow their own settings switches. If an explicit L2 or L3 request is disabled, Qoder CLI tells you to enable it in `/security-settings`; implicit L3 handoff checks stay silent when L3 is disabled.
## Run Repository Scans in CI/CD
`security scan` provides an L4 repository scan. It is a deterministic, non-interactive command that does not start a conversation or depend on a Skill, so you can invoke it directly from a CI/CD script.
Scan the whole repository:
```bash
qoder --cwd /path/to/repository security scan --all
```
Scan selected files or directories:
```bash
qoder --cwd /path/to/repository security scan src/auth src/payment
```
`--cwd` sets the repository working directory. Because a CI job might not run from the checkout directory, we recommend always setting it explicitly. You cannot combine `--all` with path arguments. If neither is provided, the command displays help without starting a scan.
Whole-repository and selected-path scans invoked through this CI/CD command are not subject to a 10,000-line limit. No additional option is required. Larger repositories generally take longer to scan.
Common options:
| Option | Description |
| -------------------------- | -------------------------------------------------------------------------------- |
| `--report ` | Generate a report; repeat the option to create multiple reports |
| `--fail-on ` | Exit non-zero when findings at this severity or higher exist; defaults to `high` |
| `--wait-timeout ` | Maximum time to wait for the scan result; defaults to `3600` |
| `--config ` | Use an advanced scan configuration file |
For example, generate a SARIF report and fail the pipeline on High or Critical findings:
```bash
qoder --cwd "$CI_PROJECT_DIR" security scan --all \
--fail-on high \
--report sarif=qoder-security.sarif
```
Use `--fail-on none` to observe an initial baseline without failing on findings. It does not suppress authentication, network, scan execution, report writing, or timeout errors; those errors still produce a non-zero exit code.
The environment must have valid Qoder CLI authentication and network access to the security scan service. The first run can include additional preparation time. Service-side analysis runs in stages and can take several minutes even for a small target. Early analysis is usually the longest stage, and intermediate results require further confirmation, so the command can remain quiet for a while and print results and reports near completion. This silence does not by itself mean the process is stuck. Set the CI job timeout higher than `--wait-timeout` and reserve time for report upload.
View all options:
```bash
qoder security scan --help
```
## When to Use It
Security scanning is useful in scenarios such as:
- Qoder CLI generated or modified security-sensitive code, such as authentication, payment, data export, file upload, or command execution logic.
- You want to quickly check whether the current changes introduced high-risk issues before committing or handing off code.
- You want security-focused feedback before a code review.
- You are using automated modes and want to keep a continuous safety check enabled.
- You want to scan a repository or critical directories in CI/CD and gate the pipeline by severity.
## Notes
Security scanning focuses on the current task and incremental changes. Project/file scan can scan the whole repository or selected paths, but it is still not a complete security audit and does not guarantee that every vulnerability will be found.
Results depend on the current code context, accessible files, and enabled scan levels. For critical business code, combine it with human security review, tests, dependency scanning, and your organization's security process.
If security scanning does not behave as expected, check the following:
- The relevant scan level is `on` in `/security-settings`.
- Your user-level `settings.json` does not explicitly disable fields under `securityScan`.
- If you edited the settings file manually, the JSON is valid and saved to user-level settings.
- The current task produced new or modified code that can be scanned.
## Related Docs
- [Permissions](/cli/permissions): Learn about tool approval, permission modes, and allow/deny rules.
- [Hooks](/cli/hooks): Learn how Qoder CLI runs automation during tool calls and session lifecycle events.
- [Skills](/cli/Skills): Learn how Skills extend Qoder CLI with specialized capabilities.
# Custom Models
> Connect supported third-party models through the BYOK wizard in Qoder CLI
Qoder CLI supports BYOK (Bring Your Own Key). You can use an API key obtained from a model provider to call models included in the corresponding subscription plan. Add and manage custom models from the **Custom** tab in `/model`.
**Available edition**: Individual plan
**Supported providers**: Refer to the live catalog displayed by the Custom wizard.
## Add a custom model
1. Enter `/model` in Qoder CLI.
2. Switch to the **Custom** tab.
3. Select `Add custom model...` and press `Enter`.
4. Follow the wizard to select Provider → model type → model.
5. Enter the API key and any other information requested by the wizard.
6. After validation succeeds, the configuration is saved automatically and the model is immediately available for selection.
Configure BYOK through the Custom wizard in `/model`. Do not configure BYOK manually in `settings.json`; the available providers, models, and credential fields are determined by the BYOK catalog available to the current account.
## Select a custom model
1. Enter `/model` to open the model selector.
2. Switch to the **Custom** tab.
3. Select an added model and press `Enter`.
After switching, you can use the model in the current session. For built-in models and reasoning effort, see [Models](/cli/model).
## Delete a custom model
In the **Custom** tab of `/model`, select the model and press `d` to delete it.
## Troubleshooting
- **The Custom tab or add entry is missing**: Confirm that BYOK is available for the current account and plan.
- **A provider or model is missing**: The options shown by the Custom wizard are the source of truth for the currently available catalog.
- **API key validation fails**: Check that the key is valid and that its subscription plan grants access to the selected model.
# Output Style
> Adjust the tone, verbosity, and structure of responses, overlaying instructions on top of the system prompt without altering Qoder's core identity and security constraints.
Output Style is used to adjust the tone, verbosity, and structure of Qoder CLI responses. For example, you might prefer more concise replies, a more instructional tone, or a specific structure. By selecting or customizing an output style, you can align Qoder's expression with your personal or team preferences without having to repeat instructions in every conversation.
Output Style only affects the "way of expression" and does not alter Qoder's core identity or security constraints—it merely appends additional instructions on top of the System Prompt, and cannot replace or bypass built-in behavioral guidelines.
## How to Set
The output style is specified via the configuration item `outputStyle` (top-level key), with the value being the style name:
```json
{
"outputStyle": "concise"
}
```
It is also compatible when placed under `general.outputStyle`; if configured in both places, the top-level setting takes precedence.
After modifying `outputStyle`, you need to **restart** Qoder CLI for the changes to take effect.
If you only want to use a specific style temporarily, you can specify it using the `--output-style` parameter at startup:
```shell
qoder --output-style concise
```
This parameter only applies to the current session, takes precedence over configuration items, and does not require a restart. For the full list of parameters, see [CLI Commands and Parameters](/cli/cli-reference).
If this item is not set, or if it is set to the default style, Qoder uses its built-in default expression without appending any additional style.
## Style Sources and Priority
Output styles can come from multiple sources. When styles with the same name appear in multiple sources, they are merged according to the following priority, where **the latter overrides the former**:
1. **Built-in style**: Preset styles provided with Qoder CLI.
2. **Plugin-provided styles**: Styles declared by enabled plugins.
3. **User-Level Style**: Styles from user-level configuration.
4. **Project-Level Style**: Styles from project-level configuration.
In other words, a project-level style with the same name overrides the user-level one, and the user-level one overrides plugin-provided and built-in styles.
Additionally, some plugins can declare a "forced style". When a forced style exists, it takes precedence over the style specified by `outputStyle`; if there are multiple forced styles, the first one takes effect and a warning is logged.
## Custom Output Style
In addition to using built-in and plugin-provided styles, you can also define your own styles to solidify and reuse common expression preferences.
### How to Define
Custom styles are Markdown files (`.md`) placed in specified directories, with each file defining one style:
- **User-level**: `~/.qoder/output-styles/`, applies to all projects.
- **Project-level**: `/.qoder/output-styles/`, applies only to the current project.
The file consists of an optional YAML frontmatter and the body. **The body contains the style instructions appended to the System Prompt**:
```markdown
---
name: concise-cn
description: Concise Chinese reply style
---
Keep replies as concise as possible, stating the conclusion before the reasoning.
Avoid repeating information the user already knows, and include only the essential parts in code examples.
```
| frontmatter Field | Required | Description |
| ----------------- | -------- | --------------------------------------------------------------------------------- |
| `name` | No | Style name; defaults to the filename (without `.md`) if omitted. |
| `description` | No | Style description; defaults to the first non-heading line of the body if omitted. |
After creation, you can enable it by referencing its name via `outputStyle` in the configuration (requires a restart to take effect). When referencing a plugin-provided style, include the plugin prefix, such as `plugin-name:style-name`.
### Writing Guidelines
Guidelines for writing custom styles:
- **Focus on expression**: Describe preferences regarding tone, verbosity, and structure rather than task logic.
- **Keep it concise**: Style instructions are appended to the System Prompt; overly long instructions will consume context.
- **Do not attempt to override security constraints**: Styles can only extend the way of expression and cannot alter Qoder's identity or security guidelines.
## Relationship with Other Mechanisms
- **Language Settings**: `language` controls the language used in responses, while `outputStyle` controls the expression style. The two can be used together.
- **Project Instructions**: The project instructions file (`AGENTS.md`) describes "how to do things in this project" and belongs to project conventions; Output Style describes "how to express" and belongs to expression preferences. They serve different purposes, see [Memory](/cli/memory).
- **UI Settings**: Output Style affects the response text itself, while UI themes, status bars, etc., affect the display layer, see [UI and Shortcuts](/cli/interface).
## Next Steps
- Configuration files and application order: [Configuration Files and Application Order](/cli/settings).
- Customize UI and shortcuts: [UI and Shortcuts](/cli/interface).
- Extend capabilities with plugins: [plugin](/cli/plugins-reference).
# UI and Shortcuts
> Themes, Status Bar, Keyboard Shortcuts, Vim Mode, and Voice Input in Qoder CLI
The interactive interface (TUI) of Qoder CLI offers customizable options such as themes, the Status Bar, Keyboard Shortcuts, Vim edit mode, and Voice Input. Properly configuring these UI options makes your terminal experience smoother and more tailored to your personal habits.
This page covers UI-related configurations and operations. For the layering and merging rules of configuration files, see [Configuration Files and Application Order](/cli/settings).
## Theme
Themes control the Color Scheme of the interface. You can switch themes in the interactive interface via `/theme`, or specify one in your configuration:
```json
{
"ui": {
"theme": "Tokyo Night",
"autoThemeSwitching": true
}
}
```
### Built-in themes
Qoder CLI provides multiple built-in themes: `AyuDark`, `AyuLight`, `AtomOneDark`, `Dracula`, `DefaultLight`, `DefaultDark`, `GitHubDark`, `GitHubLight`, `GoogleCode`, `Holiday`, `ShadesOfPurple`, `SolarizedDark`, `SolarizedLight`, `XCode`, `TokyoNight`, `ANSI`, `ANSILight`.
### Auto-Switch
`ui.autoThemeSwitching` (enabled by default) automatically switches between the default Light and Dark Theme based on the terminal's background color. The polling interval for the terminal background color is controlled by `ui.terminalBackgroundPollingInterval` (default: 60 seconds).
### Custom Theme
You can define your own Color Scheme via `ui.customThemes` and then reference its name in `ui.theme`.
## Status Bar
The Status Bar is displayed below the Input Box. The built-in default Status Bar displays information such as `model · workspace · +N -N` (model name, Working Directory, lines of code added/removed) and automatically hides lower-priority segments when the terminal width is insufficient.
### Custom Status Bar Command
You can run a custom shell command to generate the Status Bar content. This command receives session data as JSON via stdin (including Session ID, Working Directory, model, context usage, Git branch, Vim mode, etc.), and its standard output (including ANSI colors) is displayed below the Input Box:
```json
{
"statusLine": {
"type": "command",
"command": "~/.qoder/statusline-command.sh",
"padding": 0
}
}
```
Running `/statusline` in the interactive interface leverages the built-in Status Bar configuration capabilities to automatically read your shell configuration and generate a script.
### Paragraph Color
For the built-in default Status Bar, you can customize the Paragraph Color for each segment via `statusLine.colors` (e.g., `model`, `branch`, `separator`). Color values can be hexadecimal (e.g., `#ff6600`), ANSI names (e.g., `red`, `cyan`), or natural language color names (e.g., `ocean blue`). Leaving a value blank applies the theme's default color. The context progress bar ignores custom colors and automatically changes color (green/yellow/red) based on usage.
## Keyboard Shortcuts
Run `/shortcuts` in the interactive interface to view the current list of Keyboard Shortcuts. Common shortcuts include:
| Keyboard Shortcut | Action |
| -------------------------- | ------------------------------------------ |
| `Enter` | Submit input. |
| `Shift+Enter` / `Ctrl+J` | New line (without submitting). |
| `Ctrl+C` | Interrupt current operation / clear input. |
| `Ctrl+D` | Exit. |
| `Ctrl+A` / `Home` | Move to the beginning of the line. |
| `Ctrl+E` / `End` | Move to the end of the line. |
| `Ctrl+Left` / `Alt+Left` | Move one word to the left. |
| `Ctrl+Right` / `Alt+Right` | Move one word to the right. |
| `Ctrl+W` | Delete the word before the cursor. |
| `Ctrl+K` | Delete to the end of the line. |
| `Ctrl+U` | Delete to the beginning of the line. |
| `Ctrl+P` / `Ctrl+N` | Browse history (up/down). |
| `Ctrl+R` | Reverse search history. |
| `Shift+Up` / `Shift+Down` | Scroll up / down. |
| `Ctrl+X` | Open External Editor to edit input. |
| `Ctrl+V` | Paste clipboard content. |
| `Alt+V` | Paste clipboard image. |
| `Shift+Tab` | Toggle Permission Mode. |
| `Ctrl+Y` | Toggle Bypass Permissions Mode. |
| `Ctrl+T` | Expand to view the full Task list. |
| `Ctrl+L` | Clear screen. |
> Specific keys may vary slightly across different terminals and platforms; please refer to the mappings displayed by `/shortcuts`.
## External Editor
Run `/editor` to configure the External Editor used for editing input. Once configured, pressing `Ctrl+X` opens the current input content in that editor, which is ideal for writing longer prompts.
## Vim mode
Run `/vim` to toggle Vim edit mode. Once enabled, the Input Box supports common Vim operations:
- **Movement**: `h` / `j` / `k` / `l` (left/down/up/right).
- **Word movement**: `w` (next word), `b` (previous word), `e` (end of word).
- **Line start/end**: `0` (beginning of line), `$` (end of line).
- **Enter edit mode**: `i` (insert), `a` (append), `o` (new line).
- **Edit operations**: `d` (delete), `c` (change), `y` (yank), `x` (delete character).
- **Undo/Redo**: `u` (undo), `Ctrl+R` (redo).
The Status Bar displays the current Vim mode (INSERT / NORMAL).
## Voice Input
Run `/voice` to enable Voice Input, which converts speech to text via speech recognition. The speech recognition service address can be specified via the Environment Variable `QODER_ASR_URL`.
## Other UI Options
The `ui` group contains many other adjustable options. Common ones include:
| Configuration Item | Default | Description |
| ------------------------------- | ------- | --------------------------------------------------------------- |
| `ui.hideBanner` | `false` | Hide Startup banner. |
| `ui.hideFooter` | `false` | Hide Footer. |
| `ui.showLineNumbers` | `true` | Show line numbers in conversations. |
| `ui.loadingPhrases` | `off` | Display during loading: `tips` / `witty` / `all` / `off`. |
| `ui.dynamicWindowTitle` | `true` | Dynamically update the terminal window title with status icons. |
| `ui.accessibility.screenReader` | `false` | Screen Reader Mode, outputs plain text (requires restart). |
For a complete list of UI configuration items, see [Configuration Item Reference](/cli/settings-reference).
## Next step
- Configuration Files and Application Order: [Configuration Files and Application Order](/cli/settings).
- Adjust response phrasing: [Output Style](/cli/output-styles).
- All configuration items and Environment Variables: [Configuration Item Reference](/cli/settings-reference).
# Network, Proxy, and VPC
> Configure proxy, certificates, DNS, and browser behavior for Qoder CLI
Qoder CLI requires network access to perform operations such as authentication, model inference, web search, and web scraping. In corporate intranets, proxy environments, or restricted networks, you may need to configure a proxy, certificates, or custom DNS behavior. This page covers the relevant environment variables and configuration methods.
Most network settings are controlled via standard environment variables, so you can directly apply your existing terminal network configuration practices.
## Proxy
Qoder CLI supports standard HTTP/HTTPS proxy environment variables:
| Variable | Description |
| ----------------------------- | ------------------------------------------------------ |
| `HTTPS_PROXY` / `https_proxy` | The proxy address used for HTTPS requests. |
| `HTTP_PROXY` / `http_proxy` | The proxy address used for HTTP requests. |
| `NO_PROXY` / `no_proxy` | A comma-separated list of hosts that bypass the proxy. |
Example:
```bash
export HTTPS_PROXY=http://127.0.0.1:7890
export HTTP_PROXY=http://127.0.0.1:7890
export NO_PROXY=localhost,127.0.0.1,.internal.example.com
qoder
```
Notes:
- Proxies are read at startup; you must restart Qoder CLI after making changes.
- Both uppercase and lowercase forms (e.g., `HTTPS_PROXY` and `https_proxy`) are recognized, though some tools require the lowercase form.
- When the sandbox is enabled, proxy settings are forwarded to the sandbox environment, ensuring that requests from within the sandbox also route through the proxy.
## Certificates
In networks using self-signed certificates or enterprise root certificates, you can specify additional trusted certificates via standard Node.js environment variables:
| Variable | Description |
| --------------------- | -------------------------------------------------------------- |
| `NODE_EXTRA_CA_CERTS` | The path to an additional CA certificate file (in PEM format). |
| `SSL_CERT_FILE` | Specifies the path to the certificate file. |
Example:
```bash
export NODE_EXTRA_CA_CERTS=/path/to/corp-root-ca.pem
qoder
```
If you encounter certificate validation failures (such as `unable to verify the first certificate`), you typically need to configure the above variables to point to the correct root certificate.
## DNS
For environments with specific requirements for DNS resolution order, you can use the `advanced.dnsResolutionOrder` configuration item to specify the resolution order (e.g., prioritizing IPv4 or following the system's return order). A restart is required after modifying this setting.
## Browser Behavior
By default, processes such as sign-in and authentication attempt to open a browser to complete the callback. The CLI automatically detects environments without a graphical interface and skips launching the browser, printing a link you can copy manually instead—an environment is treated as having no graphical interface if any of the following conditions is met:
- `CI` is set;
- `BROWSER=www-browser`;
- `DEBIAN_FRONTEND=noninteractive`;
- inside an SSH session (`SSH_CONNECTION`);
- on Linux with none of `DISPLAY`, `WAYLAND_DISPLAY`, or `MIR_SOCKET` set.
Therefore, no extra configuration is needed in SSH remote sessions, containers, or CI environments. For more details on authentication, see [Sign-in and Authentication](/cli/authentication).
## Network in the Sandbox
When the sandbox is enabled, network access is disabled by default (`tools.sandboxNetworkAccess` defaults to `false`). If you need network access within the sandbox, you must explicitly enable this option. Proxy-related environment variables are forwarded into the sandbox.
## Troubleshooting
- **Connection timeouts or inaccessible resources**: Verify that the proxy variables are set correctly and that `NO_PROXY` does not omit any necessary intranet domains.
- **Certificate errors**: Configure `NODE_EXTRA_CA_CERTS` to point to the enterprise root certificate.
- **Browser fails to open during sign-in**: In environments without a graphical interface, the CLI automatically skips launching the browser and prints the sign-in link; manually copy it into a browser to open it. You can also switch to Personal Access Token authentication instead.
For more detailed network troubleshooting, see [Network, Proxy, and VPC Issues](/cli/troubleshoot-network).
## Next Steps
- Sign-in and Authentication: [Sign-in and Authentication](/cli/authentication).
- Network Troubleshooting: [Network, Proxy, and VPC Issues](/cli/troubleshoot-network).
# CLI Commands and Parameters
> Complete reference for all qoder command-line startup parameters, flags, default values, and usage examples.
This page lists all startup parameters and flags for the `qoder` command. Use `qoder --help` in the terminal to view the complete list.
Basic invocation:
```bash
qoder [options] [prompt text]
```
When no arguments are passed, it enters an interactive session. Passing a text prompt or `--print` switches to Non-Interactive Mode.
## General Flags
| Flag | Short | Type | Description |
| -------------- | ----- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `--version` | `-v` | boolean | Print the version number and exit. |
| `--help` | `-h` | boolean | Display help information and exit. |
| `--debug` | `-d` | boolean | Enable debug log output. |
| `--cwd` | `-w` | string | Specify the Working Directory (defaults to the current directory). |
| `--config-dir` | | string | Override the User Configuration Directory (default `~/.qoder`). |
| `--add-dir` | | string\[] | Add Additional trusted directories for the current session (can be used multiple times). |
| `--attachment` | | string | Attach files to the initial prompt (can be used multiple times). |
| `--worktree` | | `[name]` | Execute in isolation within a new Git Worktree, merging results back to the main branch; the name is optional and auto-generated if omitted. |
## Models and Reasoning
| Flag | Short | Type | Description |
| -------------------- | ----- | ------- | ---------------------------------------------------------------------------------- |
| `--model` | `-m` | string | Specify the Model Identifier (e.g., `auto`, `lite`, `performance`, or a BYOK key). |
| `--reasoning-effort` | | string | Override the reasoning effort for this session (e.g., `high`). |
| `--context-window` | | number | Override the Context Window size (in tokens) for this session. |
| `--list-models` | | boolean | List available models and exit. |
| `--output-style` | | string | Name of the active Output Style. |
## Session Management
| Flag | Short | Type | Description |
| ------------------ | ----- | --------- | ------------------------------------------------------------------------------------- |
| `--continue` | `-c` | boolean | Resume the most recent session. |
| `--resume` | `-r` | `[id]` | Restore a Historical session by identifier; if no ID is provided, select from a list. |
| `--session-id` | | string | Resume the session with the specified ID. |
| `--fork-session` | | boolean | Fork a new session from a restored session (use with `--resume`/`--session-id`). |
| `--name` | `-n` | string | Set or override the current session name. |
| `--list-sessions` | | boolean | List all historical sessions and exit. |
| `--delete-session` | | `` | Delete a specific session by its index number. |
> **Conflict Rules**: `--continue`, `--resume`, `--remote`, `--remote-session`, `--teleport`, and `--remote-control` cannot be used simultaneously.
## Output and Script Mode
| Flag | Short | Type | Description |
| -------------------------- | ----- | ------- | -------------------------------------------------------------------------------------------------------- |
| `--print` | `-p` | boolean | Non-Interactive Mode: output a single response and exit (ideal for CI/scripts). |
| `--output-format` | `-o` | enum | Output format: `text` (default), `json`, `stream-json`. |
| `--input-format` | | enum | Input format: `text` (default), `stream-json`. |
| `--max-turns` | | number | Limit the maximum Conversation Turns per query (used in automation scenarios to prevent infinite loops). |
| `--max-output-tokens` | | number | Set the maximum number of tokens for a single model output. |
| `--prompt-interactive` | `-i` | string | Execute the given prompt first, then enter interactive mode. |
| `--no-session-persistence` | | boolean | Do not write the session to disk; it cannot be restored (only valid under `--print`). |
## Permission Control
| Flag | Short | Type | Description |
| -------------------------------- | ----- | ------- | ---------------------------------------------------------------------------------------------------------- |
| `--permission-mode` | | enum | Set the Permission Mode: `default` / `plan` / `auto` / `bypass_permissions` / `accept_edits` / `dont_ask`. |
| `--yolo` | | boolean | Equivalent to `--permission-mode bypass_permissions` (dangerous: skips all permission confirmations). |
| `--dangerously-skip-permissions` | | boolean | Same as `--permission-mode bypass_permissions` (dangerous: skips all permission confirmations). |
## Tools and MCP
| Flag | Short | Type | Description |
| ----------------------------- | ----- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--tools` | | string\[] | Restrict available Built-in tools, separated by spaces or commas (`""` disables all, `default` enables all; use `-p` or `--` to separate from the query). |
| `--allowed-tools` | | string\[] | Allowlist of tools permitted for use. |
| `--disallowed-tools` | | string\[] | Blocklist of tools prohibited from use. |
| `--mcp-config` | | string | Path to the MCP configuration file (JSON). |
| `--strict-mcp-config` | | boolean | Strict mode: only load MCP servers specified by `--mcp-config`. |
| `--allowed-mcp-server-names` | | string\[] | Allowlist of permitted MCP server names. |
| `--max-model-request-retries` | | number | Maximum number of retries for Qoder and external provider model requests. |
## Sandbox
| Flag | Short | Type | Description |
| ----------- | ----- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `--sandbox` | `-s` | boolean | Enable the Sandbox (boolean switch, does not accept backend names). The backend is specified by `QODER_SANDBOX` or `tools.sandbox`. |
## Agent and System Prompt
| Flag | Short | Type | Description |
| ------------------------ | ----- | ------ | ----------------------------------------------- |
| `--agent` | | string | Specify the Agent name used by the main thread. |
| `--agents` | | json | Define a custom Agent using a JSON object. |
| `--system-prompt` | | string | Override the System Prompt. |
| `--append-system-prompt` | | string | Append content after the default System Prompt. |
## Configuration Overrides
| Flag | Short | Type | Description |
| ------------------- | ----- | --------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `--settings` | | string | Path to a JSON file or an inline JSON object (parsed as inline if it starts with `{`), serving as the highest priority configuration. |
| `--setting-sources` | | string\[] | Specify the list of configuration sources to load. |
| `--plugin-dir` | | string | Additional plugin search directory. |
## Remote and Collaboration
| Flag | Short | Type | Description |
| ------------------ | ----- | -------- | ----------------------------------------------------------------------------------------- |
| `--remote` | | `[task]` | Create a cloud remote session and print the access URL (optionally with an initial task). |
| `--remote-session` | | `` | Cold load and connect to an existing remote session. |
| `--teleport` | | `` | Load and connect to a remote session. |
| `--remote-control` | | `` | Run as a headless remote-control worker. |
## Editor Integration
| Flag | Short | Type | Description |
| ------- | ----- | ------- | ----------------------------------------------------------------------------------------------------------------------- |
| `--acp` | | boolean | Start as an ACP server for integration via standard input/output by clients implementing the ACP protocol, such as Zed. |
## Subcommands
In addition to startup parameters, `qoder` also provides several subcommands in the form of `qoder `:
| Subcommand | Description |
| -------------------------- | --------------------------------------------- |
| `mcp` | Configure and manage MCP servers. |
| `plugins` (alias `plugin`) | Manage plugins. |
| `skills` (alias `skill`) | Manage Agent Skills. |
| `hooks` (alias `hook`) | Manage Hooks. |
| `agents` (alias `agent`) | Manage Agents. |
| `login` | Sign in to your account. |
| `commit` | Generate a commit message and commit changes. |
| `rollback` | Roll back to a previous version. |
| `update` | Update to the latest version. |
| `remote-control` | Start the remote-control daemon. |
| `status` | Display session status. |
| `feedback` | Submit feedback. |
| `wiki` | Generate Wiki documentation for the project. |
## Usage Examples
```bash
# Start in interactive mode
qoder
# Specify model
qoder -m performance
# Non-interactive one-shot execution
qoder -p "Explain what this code does"
# JSON output for script consumption
qoder -p -o json "List project dependencies"
# Resume last session
qoder -c
# Execute in an isolated worktree
qoder --worktree "Refactor the database layer"
# Fully automated mode + sandbox
qoder --permission-mode auto -s docker "Run tests and fix failures"
```
## Next Steps
- Slash commands in interactive mode: [Slash Commands](/cli/slash-reference).
- Configuration files and environment variables: [Configurations, environment variables, and file paths](/cli/settings-reference).
- Detailed guide for non-interactive execution: [Run in Scripts](/cli/run-in-scripts).
# Slash Commands
> All built-in slash commands, aliases, and usage in Qoder CLI interactive sessions
In an interactive session, commands starting with `/` are **slash commands**, used to perform in-session operations without exiting. Typing `/` brings up the command completion list, and `/help` displays all available commands.
This page lists all built-in slash commands grouped by function. Some commands may not be visible depending on current feature flags or versions (see [Conditional Commands](#conditional-commands) at the end of this page).
## Sessions and Conversations
| Command | Description |
| ----------- | ------------------------------------------------------- |
| `/new` | Create a new empty session. |
| `/clear` | Clear the current session content. |
| `/continue` | Resume the most recent session for the current project. |
| `/resume` | Restore a historical session. |
| `/rename` | Rename the current session. |
| `/branch` | Branch a new session from the current one. |
| `/export` | Export the current session content. |
| `/copy` | Copy the last response. |
| `/compact` | Compress context to free up space. |
| `/rewind` | Roll back to a specific checkpoint. |
| `/quit` | Exit the CLI. |
## Models and Reasoning
| Command | Description |
| ----------------- | -------------------------------- |
| `/model` | Select the conversational model. |
| `/effort` | Set the reasoning effort level. |
| `/fast` | Switch to Fast Mode. |
| `/context-window` | Set the context window. |
## Work Modes
| Command | Description |
| ------------ | --------------------------------------------------------------------------------------------------------------------- |
| `/plan` | Enter Plan mode. |
| `/goal` | Manage session goals (see [Goal Command Reference](/cli/goal-reference)). |
| `/loop` | Execute prompts or commands in a recurring loop (see [Loop Command Reference](/cli/loop-reference)). |
| `/quest` | Intelligent Workflow Orchestrator that guides you through feature development step-by-step using dedicated subagents. |
| `/tasks` | Open the background task panel (aliases `/bg`, `/background`). |
| `/workflows` | Open the workflow panel (alias `/workflow-tasks`). |
| `/kanban` | Open the Kanban panel. |
## Code and Review
| Command | Description |
| --------------- | ----------------------------------------------------------------------- |
| `/diff` | View the code diff. |
| `/review` | Review code changes. |
| `/init` | Initialize the project (generate the project instructions file). |
| `/setup-github` | Configure GitHub Actions integration (not available in the CN edition). |
## Configuration and UI
| Command | Description |
| ------------- | ------------------------------------------ |
| `/settings` | Open the Settings Panel (alias `/config`). |
| `/theme` | Switch the color theme. |
| `/statusline` | Configure the status bar. |
| `/editor` | Configure editor integration. |
| `/vim` | Toggle Vim mode. |
| `/voice` | Toggle voice input. |
| `/shortcuts` | View the keyboard shortcut list. |
## Extensions and Tools
| Command | Description |
| -------------- | ------------------------------------------------ |
| `/mcp` | Manage MCP servers. |
| `/tools` | View the list of available tools. |
| `/skills` | Manage Agent Skills. |
| `/agents` | Manage Agents. |
| `/hooks` | Manage Hooks. |
| `/commands` | Reload and list all available commands. |
| `/plugins` | Manage plugins (alias `/plugin`). |
| `/marketplace` | Browse the Plugin Marketplace (alias `/market`). |
| `/memory` | Manage long-term memory. |
## Built-in Skills
The following commands are provided by built-in Skills and can also be automatically invoked by Agents on demand:
| Command | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/debug` | Debug assistant to help locate and fix issues. |
| `/verify` | Verify if results meet expectations. |
| `/simplify` | Simplify code or workflows. |
| `/security-scan` | Qoder cloud security scan (supports L2 lightweight and L3 deep review). |
| `/run` | Launch and drive the project's actual application to observe the effects of changes at runtime. |
| `/run-skill-generator` | Create or improve project-specific `run` skills. |
| `/batch` | Spawn parallel working agents in an isolated git worktree to apply batch changes across multiple files (requires the current directory to be a Git repository). |
| `/remember` | Review automatically accumulated memory entries and propose promotion suggestions (requires auto-memory to be enabled). |
| `/mcp-config` | Manage MCP server configurations. |
For the complete list and use cases, see [Built-in Agent and Skills](/cli/builtins-reference).
## Account and Status
| Command | Description |
| -------------- | ----------------------------------------------------------------- |
| `/login` | Sign in or switch authentication methods (alias `/signin`). |
| `/logout` | Sign out and clear locally cached credentials (alias `/signout`). |
| `/status` | View account and session status. |
| `/profile` | View user profile. |
| `/usage` | View usage statistics. |
| `/upgrade` | Upgrade the account subscription plan. |
| `/insights` | View insight analysis. |
| `/privacy` | Manage privacy settings. |
| `/permissions` | Manage permissions (view and adjust permission rules). |
## Remote and Other
| Command | Description |
| ----------------- | ----------------------------- |
| `/remote-control` | Remotely control the session. |
| `/remote-env` | Manage remote environments. |
| `/add-dir` | Add trusted directories. |
| `/context` | Manage context. |
| `/docs` | Open documentation. |
| `/help` | Display help information. |
| `/about` | Display about information. |
| `/feedback` | Submit feedback. |
| `/release-notes` | View the changelog. |
## Conditional Commands
Some commands are only visible or available when specific conditions are met:
- `/agents`, `/plan`, `/workflows`, `/marketplace`: Available only when the corresponding feature flags are enabled.
- `/skills`: Requires Skills support and administrator permissions to be enabled.
- `/mcp`: Displays a disabled prompt when MCP is disabled.
- `/setup-github`: Not available in the CN edition.
- If a command is turned off by a feature gate, a corresponding disabled prompt will be displayed when typed.
## Next Steps
- Command-line startup parameters: [CLI Commands and Parameters](/cli/cli-reference).
- Custom slash commands: [Custom Commands](/cli/commands).
- Goal / Scheduled / Loop command details: [Goal Command Reference](/cli/goal-reference), [Scheduled Task Reference](/cli/scheduled-reference), [Loop Command Reference](/cli/loop-reference).
# Goal Command Reference
> Complete reference for /goal subcommands, arguments, statuses, and behaviors
`/goal` is used to set a persistent goal for the current session, allowing the Agent to continuously and autonomously execute around it. This page lists all subcommands, parameters, and state behaviors. For a guide on using Goal mode, see [Continuously Achieve Goals](/cli/goal).
Running `/goal` directly (without a subcommand) is equivalent to `/goal status`, which displays the current goal status.
## Subcommands
| Subcommand | Parameters | Description |
| -------------- | ----------------------------- | ----------------------------------------------------------------------------------------- |
| `/goal set` | ` [--turns ]` | Creates or updates a goal. Automatically switches to the `auto` Permission Mode once set. |
| `/goal status` | None | Displays the description, status, Elapsed Turns, and Elapsed Time of the current goal. |
| `/goal clear` | None | Removes the current goal and restores the Permission Mode used before the goal was set. |
| `/goal pause` | None | Pauses the current goal and restores the Permission Mode. |
| `/goal resume` | None | Resumes a paused goal and re-enters the `auto` Permission Mode. |
| `/goal take` | None | Claims a goal owned by another session, transferring ownership to the current session. |
## set Parameters
`/goal set [--turns ]`
- `` (required): The natural language description of the goal. Omitting the description prompts the usage.
- `--turns ` (optional): Maximum Interaction Turns. `N` must be a positive integer; invalid values are ignored. Once the limit is reached, the goal transitions to the `TurnLimited` state.
Example:
```text
/goal set fix all failing unit tests and commit
/goal set complete login module refactoring --turns 20
```
## Status Fields
Goal status is persisted and includes the following fields:
| Field | Description |
| ----------------- | --------------------------------------------------------------------------------- |
| `objective` | Goal description. |
| `status` | Status: `Active` / `Paused` / `TurnLimited`. |
| `maxTurns` | Maximum Turn Limit (optional). |
| `turnsUsed` | Elapsed Turns. |
| `timeUsedSeconds` | Elapsed Time (in seconds). |
| `ownerSessionId` | Session ID owning the goal (used for multi-session collaboration). |
| `planWasActive` | Whether it was in Plan Mode before the goal was activated (used for restoration). |
## Key Behaviors
- **Automatic Permission Mode Switching**: `/goal set` and `/goal resume` automatically switch to the `auto` Permission Mode and lock Shift+Tab switching while the goal is active; `/goal clear` and `/goal pause` restore the previous mode (only if it is still `auto`).
- **Cross-session persistence**: Goals are persisted with the session. If the process is unexpectedly terminated while the goal is `Active`, it will automatically downgrade to `Paused` on the next startup, and can be reactivated using `/goal resume`.
- **Ownership**: The goal records the Session ID that owns it. Other sessions must first use `/goal take` to claim the goal before they can update it. This prevents a new window from silently inheriting an unfinished goal from another session.
- **Plan State Restoration**: If the goal was in Plan Mode before activation, `/goal resume` will also restore Plan Mode after a process restart.
- **Turn limit**: When `--turns` is set, the goal transitions to `TurnLimited` after `turnsUsed` reaches `maxTurns`.
## Next Step
- Goal mode guide: [Continuously Achieve Goals](/cli/goal).
- Permission Mode description: [Permissions](/cli/permissions).
- All slash commands: [Slash Command](/cli/slash-reference).
# Scheduled Task Reference
> Field-level reference for scheduled tasks: cron expression syntax, storage location, execution limits, and auto-expiration rules
Scheduled tasks allow Qoder CLI to automatically trigger a prompt or slash command at specified times. This page explains the cron expression format, storage location, and execution limits. For a usage guide on scheduled tasks, see [Scheduled Execution Task](/cli/scheduled-tasks).
## cron expression format
Scheduled tasks use standard 5-field cron expressions, **interpreted in the Local Time Zone where the CLI is running**:
```text
┌───────── Minute (0-59)
│ ┌─────── Hour (0-23)
│ │ ┌───── Day (1-31)
│ │ │ ┌─── Month (1-12)
│ │ │ │ ┌─ Day of week (0-6, 0=Sunday; 7 is also Sunday)
│ │ │ │ │
* * * * *
```
Supported field syntax:
| Syntax | Meaning | Example |
| --------- | --------------------- | ---------------------------------------------- |
| `*` | Wildcard, matches all | `* * * * *` (every minute) |
| `N` | Single value | `0 9 * * *` (9:00 every day) |
| `*/N` | Step, every N units | `*/15 * * * *` (every 15 minutes) |
| `N-M` | Range | `0 9-17 * * *` (every hour from 9 to 17) |
| `N,M,...` | List | `0 9,12,18 * * *` (at 9, 12, and 18 every day) |
> `L`, `W`, `?`, and name aliases are not supported. When both day of month and day of week are restricted, an "OR" semantics is applied—triggering if either matches (standard cron behavior).
Common examples:
| Expression | Meaning |
| -------------- | ---------------------- |
| `*/10 * * * *` | Every 10 minutes |
| `0 * * * *` | Every hour on the hour |
| `0 9 * * *` | 9:00 every day |
| `0 9 * * 1-5` | 9:00 on weekdays |
| `0 0 */2 * *` | 0:00 every 2 days |
## Storage Location
Persistent scheduled tasks are saved in the `.qoder/scheduled_tasks.json` under the project. File format:
```json
{
"tasks": [
{
"id": "a1b2c3d4",
"cron": "0 9 * * *",
"prompt": "/standup",
"createdAt": 1700000000000,
"recurring": true
}
]
}
```
Task fields:
| Field | Description |
| ------------- | ------------------------------------------------------------------------ |
| `id` | 8-character hexadecimal task identifier. |
| `cron` | 5-field cron expression. |
| `prompt` | Prompt text or slash command queued upon trigger. |
| `createdAt` | Creation timestamp (milliseconds). |
| `lastFiredAt` | Last trigger timestamp (milliseconds, written back for recurring tasks). |
| `recurring` | Whether it is a recurring task. |
## Task Types
- **One-time task** (`recurring` is false or omitted): Automatically deleted after a single trigger.
- **Recurring Task** (`recurring: true`): Triggered repeatedly on a cycle, rescheduled from the current time until explicitly deleted or automatically expired.
## Execution Limits and Expiration
- **Maximum number of tasks**: Up to **50** tasks. Once the limit is reached, existing tasks must be deleted before creating new ones.
- **Auto-expiration**: Recurring tasks automatically expire and are cleaned up **7 days** after creation (one-time tasks are deleted immediately after triggering).
- **Jitter Scheduling**: To prevent multiple sessions from triggering simultaneously, the scheduler adds a deterministic jitter delay—recurring tasks are delayed by up to 10% of their interval (capped at 15 minutes); one-time tasks are triggered up to 90 seconds early when aligned to 30-minute boundaries. Jitter is calculated based on the task ID and remains stable across restarts.
- **Missed tasks**: If a task's next scheduled run time is already in the past (missed while the process was not running), a prompt will be shown at startup.
- **Single-process driven**: A File Lock ensures that only one process drives the scheduling for the same project directory, preventing duplicate triggers.
## Creation and Deletion
- Create, list, and delete tasks using the Agent's scheduled task tool (simply request it in natural language during a conversation).
- Quickly create recurring tasks via `/loop`; see [Loop Command Reference](/cli/loop-reference).
- Recurring tasks can be manually deleted before their 7-day auto-expiration.
## Next Steps
- Scheduled task usage guide: [Scheduled Execution Task](/cli/scheduled-tasks).
- Loop execution: [Loop Command Reference](/cli/loop-reference).
# Loop Command Reference
> Parameter format, interval units, budget ceilings, default values, and cancellation methods for /loop loop execution.
`/loop` Enables Qoder CLI to repeatedly execute a prompt or slash command, either at a fixed interval (powered under the hood by the scheduled task system) or at a pace Qoder chooses for itself. This page explains its parameter format, interval conversion, budget ceilings, and cancellation methods. For a usage guide on loop execution, see [Loop Tasks](/cli/loop).
## Usage
```text
/loop [interval] [flags]
```
- `[interval]` (optional): Execution interval. Providing one selects fixed-interval mode; omitting one selects dynamic-pacing mode.
- `[flags]` (optional): Persistence and budget ceilings, listed below.
- `` (required): The prompt text or slash command to be executed repeatedly. Slash commands are passed through unchanged.
## Modes
| Mode | Selected when | Mechanism |
| -------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| Fixed-interval | The input contains an interval | The interval is converted to a cron expression and registered as a scheduled task. |
| Dynamic-pacing | The input contains no interval | After each run Qoder schedules the next wake-up itself, with a delay clamped to `[60, 3600]` seconds. Not scheduling one ends the loop. |
Special cases:
- `/loop` with no arguments: if `.qoder/loop.md` exists, Qoder loops over that task list in dynamic-pacing mode; otherwise the usage message is shown.
- `/loop 5m` (interval but no prompt): the usage message is shown.
- Flags only, with no prompt (e.g. `/loop --max-turns 3`): Qoder runs a general project health check on each iteration, in dynamic-pacing mode.
## Flags
| Flag | Value | Description |
| ------------------- | ------------ | ---------------------------------------------------------------------------- |
| `--durable` | — | Persist the task to disk so it survives restarts, with no automatic expiry. |
| `--durable d` | Days | Persist the task and expire it N days from now. |
| `--permanent`, `-p` | — | Equivalent to `--durable` with no expiry. |
| `--max-turns ` | Whole number | Stop the loop after N runs. |
| `--max-credits ` | Number | Stop the loop once N credits have been spent in total. Decimals are allowed. |
Flag parsing rules:
- Both the space form (`--max-turns 6`) and the `=` form (`--max-turns=6`) are accepted for the ceilings.
- Flags may appear anywhere in the input. They are stripped before the interval is parsed, so `/loop --max-turns 5 10m check the deploy` still reads `10m` as the interval instead of `5`.
- If a flag is repeated, the first value wins and every copy is removed from the prompt.
- `--durable` and `--permanent` apply to fixed-interval loops. A dynamic-pacing loop always lives in the current session.
## Interval Units
An interval consists of a number and a unit suffix:
| Suffix | Unit | Description |
| ------ | ------- | ------------------------------------------------------------------- |
| `s` | Seconds | Rounded up to the nearest minute (minimum granularity of 1 minute). |
| `m` | Minutes | Every N minutes. |
| `h` | Hours | Every N hours. |
| `d` | Days | Every N days (triggers at midnight local time). |
> **The minimum granularity is 1 minute**. Intervals in seconds are rounded up to `ceil(N/60)` minutes, and you will be notified of the rounding.
## Parsing Rules
After the flags are removed, `/loop` parses the remaining input with the following priority:
1. **Leading token**: If the first word matches `^\d+[smhd]$` (e.g., `5m`, `2h`), it is treated as the interval, and the rest as the prompt → fixed-interval mode.
2. **Trailing every clause**: Otherwise, if the input ends with `every ` or `every ` (e.g., `every 20m`, `every 5 minutes`), it is extracted as the interval and removed from the prompt → fixed-interval mode. This only matches when `every` is followed by a time expression—`check every PR` does not contain an interval.
3. **Otherwise**: No interval is present, and the whole input is the prompt → dynamic-pacing mode.
## Examples
```text
/loop 5m /babysit-prs # Run /babysit-prs every 5 minutes
/loop 30m check the deploy # Check the deployment every 30 minutes
/loop 1h /standup 1 # Run /standup 1 every hour
/loop run tests every 20m # Run tests every 20 minutes
/loop monitor CI pipeline # Dynamic pacing: Qoder picks the timing
/loop --durable 30d 1h /standup 1 # Persisted, expires in 30 days
/loop --max-turns 6 10m check the deploy # Stops after 6 runs
```
## Interval to cron Conversion
| Interval Pattern | cron Expression | Description |
| ---------------- | ------------------------ | ------------------------------------------------------ |
| `Nm` (N ≤ 59) | `*/N * * * *` | Every N minutes |
| `Nm` (N ≥ 60) | `0 */H * * *` | Converted to hours (H = N/60, must be divisible by 24) |
| `Nh` (N ≤ 23) | `0 */N * * *` | Every N hours |
| `Nd` | `0 0 */N * *` | Every N days at midnight |
| `Ns` | Treated as `ceil(N/60)m` | Minimum cron granularity is 1 minute |
If the interval cannot evenly divide its unit (e.g., `7m` would produce uneven intervals, `90m` cannot be expressed in cron), the closest clean interval is selected, and you will be informed of the rounding result before the task is created.
## Budget Ceilings
A ceiling is a limit to arrive at, not one to exceed: the loop stops as soon as usage reaches it. When both ceilings are set, whichever is reached first stops the loop; if both are reached at the same moment, the message reports the run ceiling.
| Ceiling | Counter | Checked | Accuracy |
| --------------- | ---------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------- |
| `--max-turns` | Number of runs over the whole life of the task | Before each run | Exact—`--max-turns 2` fires exactly twice. |
| `--max-credits` | Credits spent in total | After a run has been metered | The final run may end slightly above the ceiling; a run in progress is never cut off. |
Additional rules:
- Only positive values are accepted. The scheduling tools reject `0` or a negative number instead of silently dropping it, and a non-positive value found in an existing task file is discarded, leaving the task with no ceiling.
- Run counts are lifetime counts. Restarting Qoder CLI does not reset them.
- Reaching a ceiling is not the same as expiring. The task is removed and cannot be resumed; start a new loop to continue.
- When a ceiling is reached, both you and Qoder are notified—you see `Scheduled task stopped: it used 2 of 2 turns.` (or `Loop stopped: it used 3 of 3 turns.` in dynamic-pacing mode), and Qoder is told to report the stop rather than recreate the task.
### Persisted fields
For a durable task, the ceilings and the usage are stored alongside the other fields in `.qoder/scheduled_tasks.json`:
| Field | Description |
| ------------- | --------------------------------------------------------------------------------------------------------- |
| `fireCount` | Lifetime number of runs, compared against `maxTurns`. |
| `creditsUsed` | Credits spent in total. A missing value means the spend was never metered, which is not the same as zero. |
| `maxTurns` | Run ceiling. Absent means no ceiling. |
| `maxCredits` | Credit ceiling. Absent means no ceiling. |
Task files written before these fields existed simply have no ceilings, so they keep running as before.
### Dynamic-pacing ceilings
In dynamic-pacing mode the ceiling and the usage are held in memory for the duration of the loop:
- **Sticky**: pass the flag on the `/loop` that starts the loop and it applies to every later wake-up. Later wake-ups that do not repeat it cannot remove the ceiling.
- **Reset on stop**: stopping the loop clears both the ceiling and the usage, so the next `/loop` starts from zero rather than inheriting the previous loop's spend.
- Reaching the ceiling cancels the pending wake-up, so the loop does not wake again.
### Tool parameters
The same ceilings are available to Qoder when it schedules work itself, so you can also ask for them in natural language ("check it five times, then stop"):
| Tool | Parameters |
| ----------------------- | --------------------------------------------------------------------------------------------------- |
| Scheduled task creation | `maxTurns`, `maxCredits` — reported back in the confirmation as `Stops after N turns or M credits.` |
| Dynamic-pacing wake-up | `maxTurns`, `maxCredits` — sticky for the whole loop. |
### Panel controls
In the `/crontab` panel:
- The `USAGE` column shows `3/10 turns · 12.5/50 credits` when ceilings are set, `2 turns · 8.25 credits` when they are not, and a dash in place of the amount spent when the spend was never metered (`—/50 credits`). A task that has never run and has no ceiling leaves the column empty.
- The task detail page shows `Turns 3 / 10 (stops at the limit)` and `Credits 12.5 / 50 (stops at the limit)`.
- Press `t` to edit the run ceiling and `b` to edit the credit ceiling. An empty value clears the ceiling; a non-positive value is not accepted, and `Esc` cancels.
## Cancellation and Expiration
- Session-only recurring tasks are the default: they stop when the process exits.
- Recurring tasks automatically expire **7 days** after creation, unless created with `--durable` (no expiry) or `--durable d` (custom expiry).
- You can manually delete the corresponding scheduled task before expiration (request the Agent to delete it using natural language and provide the task ID, or delete it from the `/crontab` panel).
- In dynamic-pacing mode, asking Qoder to stop ends the loop and cancels the pending wake-up.
- After creating a recurring task, the current prompt is **executed immediately once**, without waiting for the first cron trigger.
## Next Steps
- /loop usage guide: [Loop Tasks](/cli/loop).
- Underlying mechanisms of scheduled tasks: [Scheduled Task Reference](/cli/scheduled-reference).
# Configurations, Environment Variables, and File Paths
> Comprehensive reference of all Qoder CLI configuration items, default values, environment variables, and file paths
This page lists all configuration groups, key fields, default values, and restart requirements for `settings.json`, along with supported environment variables. For configuration file layering and merging rules, see [Configuration Files and Application Order](/cli/settings).
Configuration file locations:
| Level | Path |
| ------------- | -------------------------------------- |
| User Level | `~/.qoder/settings.json` |
| Project-Level | `/.qoder/settings.json` |
| Local Level | `/.qoder/settings.local.json` |
JSON Schema is available for editor auto-completion, located in the project `schemas/settings.schema.json`.
## Top-Level Configurations
| Configuration Item | Type | Default | Restart | Description |
| ------------------- | ------- | ------- | ------- | --------------------------------------------------------------------------------------------------- |
| `mcpServers` | object | `{}` | Yes | MCP server configuration. See [MCP reference](/cli/mcp-reference). |
| `autoMemoryEnabled` | boolean | `false` | Yes | Enable Auto-Memory for interactive sessions. |
| `outputStyle` | string | None | Yes | Active output style name. Compatible with `general.outputStyle` syntax, top-level takes precedence. |
| `language` | string | None | Yes | Preferred language for AI responses (e.g., "Chinese"). |
| `vpcInstanceName` | string | None | Yes | VPC Private Deployment instance name (CN edition only). |
| `agent` | string | None | Yes | Agent name used by the main thread. |
| `enabledPlugins` | object | `{}` | Yes | Plugin enablement mapping (plugin ID → true/false). See [Plugins](/cli/plugins-reference). |
| `hooks` | object | `{}` | No | Event-based Hooks configuration. See [Hooks reference](/cli/hooks-reference). |
## general (General)
| Configuration Item | Type | Default | Restart | Description |
| --------------------------------------- | ------- | --------------------- | ------- | ------------------------------------------------------------------------------------------------ |
| `general.preferredEditor` | string | None | No | Preferred editor for opening files. |
| `general.vimMode` | boolean | `false` | No | Enable Vim Keybindings. |
| `general.defaultPermissionMode` | enum | `default` | No | Default Permission Mode: `default`/`accept_edits`/`plan`/`auto`/`bypass_permissions`/`dont_ask`. |
| `general.enableAutoUpdate` | boolean | `true` | No | Enable auto-updates. |
| `general.enableNotifications` | boolean | `false` | No | Enable run event notifications. |
| `general.maxAttempts` | number | `10` | No | Maximum retry attempts for main conversational model requests (up to 10). |
| `general.retryFetchErrors` | boolean | `true` | No | Auto-retry on network request exceptions such as `fetch failed`. |
| `general.fileCheckpointing.enabled` | boolean | `true` | Yes | Enable file checkpoints (code rollback). |
| `general.plan.enabled` | boolean | `true` | Yes | Enable Plan Mode. |
| `general.plan.directory` | string | System temp directory | Yes | Directory for storing plan artifacts. |
| `general.plan.modelRouting` | boolean | `true` | No | Auto-switch models during Plan/implementation phases. |
| `general.sessionRetention.enabled` | boolean | `true` | No | Enable automatic session cleanup. |
| `general.sessionRetention.maxAge` | string | `30d` | No | Automatically delete sessions older than this duration. |
| `general.sessionRetention.minRetention` | string | `1d` | No | Minimum retention period (safety lower bound). |
## output (Output)
| Configuration Item | Type | Default | Description |
| ------------------ | ---- | ------- | ------------------------------------ |
| `output.format` | enum | `text` | CLI output format: `text` or `json`. |
## ui (UI)
| Configuration Item | Type | Default | Restart | Description |
| -------------------------------------- | --------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `ui.theme` | string | None | No | Color theme name. |
| `ui.autoThemeSwitching` | boolean | `true` | No | Auto-switch Light and Dark Theme based on terminal background. |
| `ui.terminalBackgroundPollingInterval` | number | `60` | No | Terminal background color polling interval (seconds). |
| `ui.customThemes` | object | `{}` | No | Custom theme definitions. |
| `ui.inlineThinkingMode` | enum | `full` | No | inline thinking display: `off`/`full`. |
| `ui.dynamicWindowTitle` | boolean | `true` | No | Update window title with Status Icon. |
| `ui.hideBanner` | boolean | `false` | No | Hide Startup banner. |
| `ui.hideFooter` | boolean | `false` | No | Hide Footer. |
| `ui.hideTips` | boolean | `false` | No | Hide prompts. |
| `ui.showLineNumbers` | boolean | `true` | No | Show Line number in conversations. |
| `ui.compactToolOutput` | boolean | `true` | No | Compact display for tool output. |
| `ui.copyFullResponse` | boolean | `false` | No | `/copy` always copies the full response. |
| `ui.loadingPhrases` | enum | `off` | No | Loading display: `tips`/`witty`/`all`/`off`. |
| `ui.errorVerbosity` | enum | `low` | No | Recoverable error verbosity: `low`/`full`. |
| `ui.customWittyPhrases` | string\[] | `[]` | No | Custom loading phrases. |
| `ui.footer.*` | object | `{}` | No | Footer item configuration (items/showLabels/hideCWD/hideModelInfo, etc.). |
| `ui.rotatingInfoLine.enabled` | boolean | `true` | No | Carousel info line above the input box. |
| `ui.rotatingInfoLine.intervalMs` | number | `4000` | No | Carousel interval in milliseconds. |
| `ui.useAlternateBuffer` | boolean | `false` | Yes | Use alternate buffer. |
| `ui.accessibility.screenReader` | boolean | `false` | Yes | Screen Reader Mode, outputs plain text. |
| `ui.showMemoryUsage` | boolean | `false` | No | Display memory usage information in the UI. |
| `ui.showSpinner` | boolean | `true` | No | Show loading animation during operations. |
| `ui.terminalBuffer` | boolean | `true` | Yes | Use the new Terminal Buffer architecture for rendering. |
| `ui.renderProcess` | boolean | `true` | Yes | Enable Ink Render Process. |
| `ui.incrementalRendering` | boolean | `true` | Yes | incremental rendering, reduces flickering but may cause rendering artifacts; only supported when `ui.useAlternateBuffer` is enabled. |
## model / modelConfigs (Models)
| Configuration Item | Type | Default | Restart | Description |
| ------------------------------ | ------ | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `model.name` | string | None | No | conversational model. |
| `model.reasoningEffort` | enum | None | No | Reasoning Effort: `disabled`/`off`/`none`/`low`/`medium`/`high`/`xhigh`/`max`. |
| `model.contextWindow` | number | None | No | Explicit Context Window (tokens). |
| `model.maxSessionTurns` | number | `-1` | No | Maximum turns to retain in session, `-1` for unlimited. |
| `model.summarizeToolOutput` | object | None | No | Set output summary token budget per tool. |
| `modelConfigs.aliases` | object | Built-in | No | Model Configuration Alias presets. |
| `modelConfigs.customAliases` | object | `{}` | No | Custom aliases, merged to override built-in ones. |
| `modelConfigs.overrides` | array | `[]` | No | Apply configuration overrides based on matching conditions (primary key is model or alias); the most specific match takes effect. |
| `modelConfigs.customOverrides` | array | `[]` | No | Custom overrides, merged and appended with built-in overrides. |
## context (Context)
| Configuration Item | Type | Default | Restart | Description |
| ------------------------------------------------- | ---------------- | ----------- | ------- | ------------------------------------------------------------------------------------------------------------ |
| `context.fileName` | string/string\[] | `AGENTS.md` | No | Context file names loaded into memory. |
| `context.importFormat` | enum | None | No | Memory import format: `tree`/`flat`. |
| `context.discoveryMaxDirs` | number | `200` | No | Maximum number of directories for Memory discovery. |
| `context.memoryBoundaryMarkers` | string\[] | `['.git']` | Yes | Boundary markers for upward memory discovery. |
| `context.loadMemoryFromIncludeDirectories` | boolean | `false` | No | Load memory from Additional trusted directories. |
| `context.fileFiltering.respectGitIgnore` | boolean | `true` | Yes | Follow `.gitignore` during search. |
| `context.fileFiltering.enableRecursiveFileSearch` | boolean | `true` | Yes | Recursive search during `@` reference completion. |
| `agentsMdExcludes` | string\[] | `[]` | Yes | Exclude project-level / local-level memory files by glob. Top-level key, supports manual configuration only. |
## tools (Tools)
| Configuration Item | Type | Default | Restart | Description |
| ------------------------------- | --------------------- | ------- | ------- | ----------------------------------------------- |
| `tools.sandbox` | boolean/string/object | None | Yes | Sandbox Execution Environment. |
| `tools.sandboxAllowedPaths` | string\[] | `[]` | Yes | Additional accessible paths for the sandbox. |
| `tools.sandboxNetworkAccess` | boolean | `false` | Yes | Whether the sandbox is allowed network access. |
| `tools.shell.pager` | string | `cat` | No | Shell output paging command. |
| `tools.shell.inactivityTimeout` | number | `300` | No | Shell no-output timeout in seconds. |
| `tools.core` | string\[] | None | Yes | Built-in tool Allowlist. |
| `tools.exclude` | string\[] | None | Yes | Tool names excluded from discovery. |
| `tools.useRipgrep` | boolean | `true` | No | Use ripgrep for content search. |
| `tools.disableLLMCorrection` | boolean | `true` | Yes | Disable LLM error correction for editing tools. |
## mcp (MCP)
| Configuration Item | Type | Default | Restart | Description |
| -------------------------------- | --------- | ------- | ------- | ------------------------------------------------------------- |
| `mcp.allowed` | string\[] | None | Yes | Allowed MCP server list. |
| `mcp.excluded` | string\[] | None | Yes | Excluded MCP server list. |
| `mcp.enableAllProjectMcpServers` | boolean | `false` | Yes | Auto-approve all project-level MCP servers. |
| `mcp.enabledProjectMcpServers` | string\[] | `[]` | Yes | List of individually approved project-level MCP server names. |
| `mcp.lazyLoad` | boolean | `false` | Yes | Lazy load MCP tools (exposes Meta Tool). |
## security (Security)
| Configuration Item | Type | Default | Restart | Description |
| ----------------------------------------------- | --------- | ------- | ------- | --------------------------------------------------------------------------- |
| `security.folderTrust.enabled` | boolean | `true` | Yes | Enable Folder Trust. |
| `security.toolSandboxing` | boolean | `false` | Yes | tool-level sandbox isolation. |
| `security.disableYoloMode` | boolean | `false` | Yes | Disable `bypass_permissions` (YOLO) Permission Mode. |
| `security.blockGitExtensions` | boolean | `false` | Yes | Block installing/loading extensions from Git. |
| `security.allowedExtensions` | string\[] | `[]` | Yes | Extension source regex Allowlist. |
| `security.environmentVariableRedaction.enabled` | boolean | `false` | Yes | Enable Environment Variable Masking for variables that may contain secrets. |
| `security.enableConseca` | boolean | `false` | Yes | Enable context-aware security check. |
## permissions (Permissions)
| Configuration Item | Type | Default | Restart | Description |
| ----------------------------------- | --------- | ------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `permissions.allow` | string\[] | `[]` | No | List of automatically allowed permission rules. For rule syntax, see [Permissions](/cli/permissions). |
| `permissions.ask` | string\[] | `[]` | No | List of permission rules requiring confirmation. |
| `permissions.deny` | string\[] | `[]` | No | List of always denied permission rules. |
| `permissions.additionalDirectories` | string\[] | `[]` | No | Additional trusted directories added to workspace context (corresponding to `/add-dir`). |
| `permissions.trustDirectories` | string\[] | `[]` | No | Directories explicitly trusted by the user; stored in user-level configuration and not overridden by project-level configuration. |
| `autoMode` | object | `{}` | No | Auto mode classifier soft-steering rules (`allow`/`soft_deny`/`environment`). Top-level key, read only from user-level and local configurations. |
| `allowManagedPermissionRulesOnly` | boolean | `false` | No | Use only Managed Policy permission rules. Top-level key, primarily used for organizational managed policies. |
## privacy / aiCodeStatistics (Privacy)
| Configuration Item | Type | Default | Restart | Description |
| -------------------------------- | ------- | ------- | ------- | ------------------------------------------------- |
| `privacy.usageStatisticsEnabled` | boolean | `true` | No | Share usage data; turn off to enter Privacy mode. |
| `aiCodeStatistics.enabled` | boolean | `true` | Yes | Record and report AI-generated code statistics. |
## advanced (Advanced)
| Configuration Item | Type | Default | Restart | Description |
| ------------------------------ | --------- | ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `advanced.autoConfigureMemory` | boolean | `true` | Yes | Auto-configure Node.js memory limit. |
| `advanced.dnsResolutionOrder` | string | None | Yes | DNS resolution order. |
| `advanced.excludedEnvVars` | string\[] | `['DEBUG','DEBUG_MODE']` | No | Environment variables excluded from project context. |
| `agents.overrides` | object | `{}` | Yes | Override configuration by Agent name (enablement, tools, models, run limits, etc.). For fields, see [Subagent](/cli/builtins-reference). |
## statusLine (Status Bar)
| Configuration Item | Type | Default | Description |
| -------------------- | ------ | --------- | --------------------------------------------------------------------------------------------------- |
| `statusLine.type` | string | `command` | Status bar type. |
| `statusLine.command` | string | `""` | Shell command to generate the status bar, receives session data JSON via stdin. |
| `statusLine.padding` | number | `0` | Number of horizontal padding characters. |
| `statusLine.colors` | object | `{}` | Custom paragraph colors for the built-in default status bar (e.g., `model`, `branch`, `separator`). |
## Environment Variables
### Qoder-Related
| Environment Variable | Description |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `QODER_PERSONAL_ACCESS_TOKEN` | Personal Access Token (PAT). When set, PAT authentication is used automatically. |
| `QODER_CONFIG_DIR` | User configuration directory location (default: `~/.qoder`). |
| `QODER_MODEL` | Specifies the model to use. |
| `QODER_WORKING_DIR` | Working Directory. |
| `QODER_SESSION_ID` | Session ID. |
| `QODER_SESSION_NAME` | Session name. |
| `QODER_PERMISSION_MODE` | Permission Mode. |
| `QODER_APPEND_SYSTEM_PROMPT` | Appends to the System Prompt. |
| `QODER_MCP_LAZY` | Enables MCP Lazy Loading when set to `1`. |
| `QODER_SANDBOX` | Sandbox command or flag. |
| `QODER_SANDBOX_IMAGE` | Custom Sandbox Image. |
| `QODER_SANDBOX_IMAGE_DEFAULT` | Default Sandbox Image. |
| `QODER_SANDBOX_PROXY_COMMAND` | Internal proxy command for the sandbox. |
| `SANDBOX` | Injected by the sandbox environment to detect if already inside a sandbox to avoid nesting (usually does not need to be set manually). |
| `QODER_ASR_URL` | Speech recognition service URL. |
| `QODER_SUBAGENT_MODEL` | Model used by Subagents. |
| `QODER_MEMORY` | Enables Auto-memory when set to `1` (only applies to interactive sessions). |
| `QODER_MEMORY_USER` | Enables user-level Auto-memory when set to `1`; only takes effect when `QODER_MEMORY` is enabled. |
### Network and Proxy
| Environment Variable | Description |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `HTTP_PROXY` / `http_proxy` | Proxy address for HTTP requests. |
| `HTTPS_PROXY` / `https_proxy` | Proxy address for HTTPS requests. |
| `NO_PROXY` / `no_proxy` | Comma-separated list of hosts to bypass the proxy. |
| `NODE_EXTRA_CA_CERTS` | Path to an additional CA certificate file (PEM format). |
| `SSL_CERT_FILE` | Specifies the path to a trusted certificate file for Self-Signed Certificate or Enterprise root certificate environments. |
## Next Steps
- Configuration layering and merging rules: [Configuration Files and Application Order](/cli/settings).
- Network and proxy configuration: [Network, Proxy, and VPC](/cli/network).
# Tools
Qoder CLI uses tools to work with your local workspace and external information sources. Tools can search and read project content, modify files, run commands, fetch web content, manage context, and connect to external services through MCP.
Tools are available in both interactive TUI sessions and non-interactive print mode. The exact set of tools depends on the current session, enabled features, MCP configuration, and permission settings.
Use `/tools` in the TUI to view the tools currently available in the session.
## **Search and Explore**
Qoder CLI uses search and exploration tools to understand the current task before taking action.
| Scope | Description |
| :---------- | :-------------------------------------------------------------------------------- |
| Files | Find files in the current workspace. |
| Code | Search code, text, and configuration files. |
| Directory | Explore project structure and locate relevant paths. |
| Web | Search for external information when the task requires current or public context. |
| Web content | Retrieve content from specific web pages. |
## **Read Project Context**
Qoder CLI can read files and other project artifacts to gather context for the current request.
| Function | Description |
| :------------------------ | :---------------------------------------------------------------------- |
| View files | Read source files, documentation, configuration, and other text assets. |
| Read large files | Read a focused section when the whole file is too large. |
| Read document-like assets | Inspect supported document formats, such as PDFs, when available. |
## **Edit Files**
When a task requires changes, Qoder CLI can create or modify files in the workspace.
| Function | Description |
| :------------- | :-------------------------------------------------------------------------- |
| Modify files | Update existing files with targeted changes. |
| Create files | Add new files such as source files, tests, documentation, or configuration. |
| Edit notebooks | Modify notebook content when notebook support is available. |
File edits pass through the permission system. Depending on the permission mode and rules, Qoder CLI may apply the change directly, ask for confirmation, or block the action.
## **Execute Commands**
Qoder CLI can run shell commands when the task requires local execution.
| Function | Description |
| :------------- | :--------------------------------------------------------------------------------- |
| Run commands | Execute build, test, package, Git, inspection, or custom shell commands. |
| Run long tasks | Keep track of commands that take time, such as test suites or development scripts. |
### Background Commands and Event Monitoring
When later work does not depend on an immediate command result, Qoder CLI can run the shell command in the background and let the main session continue with other work. A command explicitly requested in the background becomes a background task regardless of how quickly it exits. When the task completes, fails, or needs attention, its result automatically returns to the owning session; you do not need to ask repeatedly or run a polling command.
```text
Background task starts -> Main session continues -> Completion returns -> Main session handles the result
```
For continuously changing signals such as logs, deployment status, or test activity, Qoder CLI can start an event monitor. Each complete line written by the monitor command becomes an event for the main session. Keep monitor commands selective so they report only useful events instead of forwarding an entire high-volume log.
In TUI, enter `/tasks` to view the status and output of background Shell and Subagent tasks and to stop tasks that are still running. When a background task ends, its completion notification returns to the main session so Qoder CLI can continue based on the result.
Shell commands usually carry more risk than read-only actions. Use permission rules to allow routine commands and ask or deny sensitive ones.
When the shell command prefix is enabled, Bash tool commands run through the configured executable wrapper after the complete shell command has been assembled. Permission checks and command displays continue to use the original command. The wrapper must execute its single command argument and preserve the process I/O and exit status.
## **Manage Context**
Some tools help Qoder CLI keep track of the current task and conversation state.
| Function | Description |
| :-------------------- | :------------------------------------------------------------------------- |
| Track tasks | Maintain a lightweight plan or task list while work is in progress. |
| Ask for clarification | Request user input when a decision or missing detail blocks progress. |
| Manage memory | Store durable information when memory features are available. |
| Use skills | Load specialized instructions or workflows when configured. |
| Plan work | Enter or exit Plan mode when the task should be analyzed before execution. |
Memory and skills provide context to the model, but they are not security boundaries. Use permissions and hooks to enforce hard policy.
## **Delegate and Automate**
Qoder CLI can use delegation and automation capabilities when they are enabled for the current environment.
| Function | Description |
| :------------- | :----------------------------------------------------------------- |
| Subagents | Delegate focused work to specialized agents. |
| Workflows | Run configured workflows for repeatable tasks. |
| Goals | Track and execute longer-running objectives. |
| Worktrees | Work in a separate Git worktree when parallel sessions are needed. |
| Scheduled work | Create or manage scheduled tasks when scheduling is enabled. |
Availability depends on product configuration, feature flags, and the current session.
## **MCP Tools**
Qoder CLI can connect to Model Context Protocol (MCP) servers to use external tools and data sources. After an MCP server is configured, its tools appear in the same `/tools` view and go through the same permission system.
MCP tools are useful for integrating with systems such as issue trackers, code hosts, databases, browser automation, internal platforms, or custom company services.
For MCP setup, see [MCP Servers](/cli/mcp-servers).
## **Control Tool Usage**
Tool visibility and tool execution are controlled separately.
| Control | Description |
| :----------------------------------------------------------- | :----------------------------------------------------- |
| `--tools` | Limits which tools are visible in the current session. |
| `--allowed-tools` | Pre-approves selected tools or tool patterns. |
| `--disallowed-tools` | Blocks selected tools or tool patterns. |
| `permissions.allow` / `permissions.ask` / `permissions.deny` | Persistent permission rules in settings files. |
| `tools.exclude` | Removes tools from discovery at startup. |
Examples:
```shell
# Read-only exploration
qoder --tools Read Grep Glob --allowed-tools 'Read,Grep,Glob'
# Allow a routine status command
qoder --allowed-tools 'Read,Grep,Bash(git status)'
# Block file edits in a non-interactive review
qoder -p "review this repository" --disallowed-tools 'Write,Edit'
```
For permission modes, rule syntax, and decision order, see [Permissions](/cli/permissions). For hooks that intercept tool calls, see [Hooks](/cli/hooks).
# Built-in Agents and Skills
> List and use cases of built-in subagents and Bundled Skills in Qoder CLI
Qoder CLI includes a built-in set of subagents and skills that are ready to use without any installation. This page lists their names and purposes. For information on how to use extended capabilities, see [Built-in Capabilities Overview](/cli/built-ins).
## Built-in Subagents
Subagents are independent execution units spawned by the main agent to handle specific types of tasks in isolation.
| Agent | Purpose | Constraints |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `general-purpose` | General-purpose agent for handling most user requests and complex multi-step tasks. | Access to all tools. |
| `Explore` | Explore agent for read-only code retrieval and understanding; thoroughness can be specified (fast / medium / very thorough). | Read-only; write and state-changing tools are disabled; uses a lightweight model. |
| `Plan` | Plan agent for designing implementation plans, providing steps, key files, and architectural trade-offs. | Read-only; write and state-changing tools are disabled; inherits the current session model. |
| `statusline-setup` | Assists in configuring the status bar. | Available only in the interactive interface (not registered in SDK mode). |
| `qoder-guide` | Answers questions about Qoder CLI features and usage. | Available only in the interactive interface (not registered in SDK mode); read-only toolset. |
> You can use the `agents.overrides` configuration item to override models, tools, or runtime configurations for specific agents, or to disable an agent. For custom agents, see [Subagents](/cli/builtins-reference).
## Built-in Bundled Skills
Skills are reusable templates for specialized capabilities, invoked via `/skill-name` or automatically called by the agent on demand.
| Skill | Purpose |
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `loop` | Executes prompts or slash commands repeatedly at fixed intervals. See [Loop Command Reference](/cli/loop-reference). |
| `remember` | Reviews auto-accumulated memory entries, suggests promotions to instructions files, and identifies outdated, conflicting, and duplicate entries (requires auto-memory to be enabled). |
| `run` | Launches and drives the project's actual application to observe the effects of changes at runtime. |
| `run-skill-generator` | Creates or improves project-specific `run` skills—that is, instructs the agent on how to build, launch, and drive the project's application; suitable for configuring projects, writing run instructions, or verifying build/run steps. |
| `batch` | Spawns parallel working agents in isolated git worktrees to apply bulk changes across multiple files (requires the current directory to be a Git repository). |
| `debug` | Debug assistant that helps locate and fix issues. |
| `quest` | Intelligent Workflow Orchestrator that guides feature development through dedicated subagents. |
| `verify` | Validates whether results meet expectations. |
| `security-scan` | Qoder cloud security scan (supports L2 lightweight and L3 deep review). |
| `simplify` | Simplifies code or processes. |
| `mcp-config` | Manages MCP server configurations. |
## Next Steps
- Overview of built-in capabilities: [Built-in Capabilities Overview](/cli/built-ins).
- Custom skills: [Skills](/cli/builtins-reference).
- Custom agents: [Subagents](/cli/builtins-reference).
# Hooks reference
> Hook event types, matching rules, execution methods, input and output, and exit codes
Hooks allow you to automatically execute custom logic at specific points in the Qoder CLI lifecycle—for example, validating before a tool call, injecting context at the start of a session, or triggering external processes on file changes. This page is the complete reference for Hooks. For a usage guide, see [Hook](/cli/hooks-reference).
## Event Types
Hooks can be bound to the following events:
| Event | Trigger |
| -------------------- | --------------------------------------- |
| `PreToolUse` | Before a tool call. |
| `PostToolUse` | After a successful tool call. |
| `PostToolUseFailure` | After a failed tool call. |
| `UserPromptSubmit` | When the user submits a prompt. |
| `SessionStart` | When a session starts. |
| `SessionEnd` | When a session ends. |
| `Stop` | When the main agent stops responding. |
| `StopFailure` | When the stop process fails. |
| `SubagentStart` | When a subagent starts. |
| `SubagentStop` | When a subagent stops. |
| `PreCompact` | Before context compression. |
| `PostCompact` | After context compression. |
| `Notification` | When a notification is generated. |
| `ConfigChange` | When configuration changes. |
| `InstructionsLoaded` | After loading project instructions. |
| `CwdChanged` | When the working directory changes. |
| `FileChanged` | When a file changes. |
| `WorktreeCreate` | When a worktree is created. |
| `WorktreeRemove` | When a worktree is removed. |
| `Elicitation` | When an elicitation is initiated. |
| `ElicitationResult` | When elicitation results are returned. |
| `TaskCreated` | When a task is created. |
| `TaskCompleted` | When a task is completed. |
| `PermissionRequest` | When a permission request is initiated. |
| `PermissionDenied` | When permission is denied. |
| `TeammateIdle` | When a collaborator is idle. |
| `Setup` | During initial installation. |
For each event's matcher fields, additional stdin input fields, blocking support, and available `hookSpecificOutput` fields, see the "Event Catalog" section in [Hook](/cli/hooks-reference).
## Hook Types
Each Hook specifies its execution method via `type`:
| Type | Description |
| --------- | --------------------------------------------------------------------------------------------------------------------------- |
| `command` | Executes a shell command. |
| `http` | Sends an HTTP request. |
| `prompt` | Makes an independent single-turn model call for decision-making; the model returns `{ ok, reason }`, and `ok=false` blocks. |
| `agent` | Starts a subagent for validation, returning `{ ok, reason }` via `StructuredOutput`, and `ok=false` blocks. |
For the complete fields of each type (such as `url`/`headers` for `http`, and the return conventions for `prompt` and `agent`), see the "Hook Entry Types" section in [Hook](/cli/hooks-reference).
## Definition Structure
Hooks are configured by event within the `hooks` group in `settings.json`. Each event corresponds to a set of Hook definitions:
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "./scripts/check.sh" }
]
}
]
}
}
```
Hook definition (group) fields:
| Field | Description |
| --------- | ------------------------------------------------------------------------------------- |
| `matcher` | Matching rules (see below), determining which targets this group of Hooks applies to. |
| `hooks` | An array of Hooks, each containing `type` and corresponding parameters. |
In addition to `type` and type-specific parameters, a single Hook entry also supports fields such as `name`, `timeout`, `if`, and `async` (executes in the background without blocking the main process). For the complete list, see the "Hook Entry Types" section in [Hook](/cli/hooks-reference).
## Matching Rules
`matcher` determines which targets (such as tool names) the Hook applies to:
- **Empty or `*`**: Matches all.
- **Exact value**: Such as `Bash`, matches only that target.
- **Pipe `|`**: Multiple values, such as `Bash|Edit|Write`.
- **Regex**: Supports regular expression matching.
More granular `if` conditions can be written as `"ToolName"` or `"ToolName(arg_glob)"`, where `arg_glob` uses glob patterns to match tool parameters.
## Input and Exit Codes
### Input (stdin)
A Hook receives a JSON object via stdin containing the current context (the following are common fields for all events; for event-specific fields, see the "Event Catalog"):
| Field | Description |
| ----------------- | ---------------------------------------------- |
| `session_id` | The current session ID. |
| `transcript_path` | The path to the session log file. |
| `cwd` | The current working directory. |
| `hook_event_name` | The name of the triggered event. |
| `permission_mode` | The current permission mode. |
| `agent_id` | The ID of the triggered Agent (if applicable). |
| `agent_type` | The Agent type (if applicable). |
### Exit Codes
`command` type Hooks control the flow via exit codes:
| Exit Code | Meaning |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0` | Success. stdout can output JSON for the CLI to parse. |
| `2` | Block. stderr content is returned as feedback to the Agent (only effective for events that support blocking; see the "Event Catalog" for event-by-event details). |
| Other | Non-blocking error; logged but does not interrupt the flow. |
When the exit code is `0`, JSON can be returned via stdout for more granular control. For the complete fields (`continue`, `stopReason`, `suppressOutput`, `systemMessage`, `decision`, `reason`, `hookSpecificOutput`), see the "Writing Hook Scripts" section in [Hook](/cli/hooks-reference).
## Hooks in Plugins
Plugins can include Hooks, configured in `hooks/hooks.json` under the plugin directory, following the same format as the `hooks` group in `settings.json`. See [Plugin Reference](/cli/plugins-reference).
## Next Steps
- Hooks usage guide: [Hook](/cli/hooks-reference).
- Extension troubleshooting: [Hooks, MCP, and plugin issues](/cli/troubleshoot-extensions).
# MCP reference
> Transport methods, configuration fields, scope, and permissions for MCP servers
The Model Context Protocol (MCP) allows Qoder CLI to integrate with third-party tools and services. This page provides a complete reference for MCP server configuration. For a usage guide, see [MCP Servers](/cli/mcp-reference).
## Transport Methods
MCP servers specify the transport protocol via the `type` field:
| Type | Description |
| -------------------------- | --------------------------------------------------- |
| `stdio` (default) | Spawns a subprocess and interacts via stdin/stdout. |
| `sse` | Connects via Server-Sent Events over HTTP. |
| `http` / `streamable-http` | Connects via HTTP (JSON-RPC + optional streaming). |
| `ws` | Connects via WebSocket / TCP. |
| `sdk` | Built-in SDK-level server (in-process). |
## Configuration Fields
MCP servers are configured under the `mcpServers` field in `settings.json`, where each key represents a server name:
```json
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["./mcp-server.js"],
"env": { "API_KEY": "..." },
"cwd": "/path/to/dir"
}
}
}
```
### stdio Type
| Field | Type | Description |
| --------- | --------- | ----------------------------------------------- |
| `command` | string | The command to start the server. |
| `args` | string\[] | Arguments passed to the command. |
| `env` | object | Environment variables passed to the subprocess. |
| `cwd` | string | The working directory for the subprocess. |
### sse Type
| Field | Type | Description |
| --------- | ------- | ------------------------------------------ |
| `url` | string | The SSE endpoint URL. |
| `type` | `"sse"` | Transport type identifier. |
| `headers` | object | HTTP headers (may include authentication). |
### http / streamable-http Type
| Field | Type | Description |
| --------- | -------- | -------------------------- |
| `url` | string | The HTTP endpoint URL. |
| `type` | `"http"` | Transport type identifier. |
| `headers` | object | HTTP headers. |
### ws Type (TCP)
| Field | Type | Description |
| ------ | ------ | -------------------------------------- |
| `tcp` | object | TCP connection parameters (host/port). |
| `type` | `"ws"` | Transport type identifier. |
### Common Optional Fields
| Field | Type | Description |
| -------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `timeout` | number | Connection/request timeout (in milliseconds). |
| `type` | string | Explicitly specifies the transport type. |
| `description` | string | Server description, displayed in the management view. |
| `trust` | boolean | Trusts the server, skipping confirmation when its tools are called. |
| `includeTools` | string\[] | Registers only the listed tools. |
| `excludeTools` | string\[] | Excludes the listed tools. |
| `disabled` | boolean | Disables the server (keeps the configuration without deleting it). |
| `alwaysAllow` | string\[] | List of tool names that are always allowed without confirmation. |
| `oauth` | object | OAuth authorization configuration (fields include `enabled`, `clientId`, `clientSecret`, `authorizationUrl`, `tokenUrl`, `scopes`, `callbackPort`, etc.). |
## Configuration Scope
MCP servers can be configured at multiple levels:
| Level | Location | Description |
| ------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| User Level | `~/.qoder/settings.json` → `mcpServers` | Available to all projects. |
| Project-Level | `/.qoder/settings.json` → `mcpServers` | Requires approval before use (for security reasons). |
| Project-Level | `/.mcp.json` | Requires a top-level `mcpServers` key; requires approval before use. |
| Local Level | `/.qoder/settings.local.json` → `mcpServers` | Local to the current project on this machine; the default scope for `-s`, loaded only when the directory is trusted. |
| Plugin | `.mcp.json` or `mcp.json` in the plugin directory | Loaded upon plugin installation. |
| CLI argument | `--mcp-config `, `--settings` | Valid for this session only. |
Servers with the same name are overridden in the following order (later overrides earlier): User Level → Project-Level `settings.json` → Project-Level `.mcp.json` → Local Level → CLI argument.
Project-level MCP servers require individual approval by default. This can be bypassed using the following methods:
- `mcp.enableAllProjectMcpServers: true`: Automatically approves all project-level servers.
- `mcp.enabledProjectMcpServers`: Allowlist, approves by name.
Both settings are placed under the `mcp` group in `settings.json` (a restart is required after modification):
```json
{
"mcp": {
"enableAllProjectMcpServers": true,
"enabledProjectMcpServers": ["playwright", "context7"]
}
}
```
## Permissions and Security
- MCP tools are managed by the Permissions System just like built-in tools—user confirmation is required before invocation (unless using `auto` or `bypass_permissions` mode).
- `--allowed-mcp-server-names`: Restricts loading to only MCP servers with specified names.
- `--strict-mcp-config`: Strict mode, loads only servers from the file specified by `--mcp-config`.
- `mcp.allowed` / `mcp.excluded`: Controls the allowlist or blocklist of servers in the configuration.
## Lazy Loading Mode
When multiple MCP servers are connected, all tool schemas are registered at startup by default, which may consume a significant number of Prompt Tokens in the first turn.
When lazy loading is enabled (`mcp.lazyLoad: true` or `QODER_MCP_LAZY=1`), the CLI exposes only three Meta Tools (`mcp_list` / `mcp_get` / `mcp_call`) and loads the actual tools on demand, saving token overhead.
## Management Commands
Use the `/mcp` Slash Command to manage MCP servers in an interactive session:
- `/mcp` — View the list and status of connected servers.
- `/mcp reload` (alias `/mcp refresh`) — Rediscover MCP servers and tools, useful after adding or modifying configurations.
Use the `qoder mcp` subcommand in the command line for non-interactive management:
- `qoder mcp add -- ` — Add a stdio server.
- `qoder mcp list` — List configured servers.
- `qoder mcp remove ` — Remove a server.
For arguments and examples for each subcommand, see [MCP Servers](/cli/mcp-reference).
## Next Steps
- MCP usage guide: [MCP Servers](/cli/mcp-reference).
- Full configuration reference: [Configurations, environment variables, and file paths](/cli/settings-reference).
- Extension troubleshooting: [Hooks, MCP, and plugin issues](/cli/troubleshoot-extensions).
# Plugin Reference
> Field-level reference for plugin.json fields, directory layout, and Marketplace Schema; see the Plugin page for usage guides.
Plugins are installable extension packages that add commands, agents, skills, hooks, output styles, workflows, and MCP servers to Qoder CLI. This page provides a complete reference for the plugin manifest, directory structure, and marketplace schema. For usage guidelines, see [Plugins](/cli/plugins-reference).
## Plugin Manifest (plugin.json)
The manifest file is located at `.qoder-plugin/plugin.json` and **must not be placed in the plugin root directory**. This file is optional—if omitted, the CLI loads components from conventional directories and uses the plugin directory name as the plugin name. However, it is recommended to declare it to ensure stable metadata such as `name` and `version`.
### Required Fields
In `plugin.json`, only `name` is required; all other fields are optional.
| Field | Type | Description |
| ------ | ------ | ------------------------------------------------------------- |
| `name` | string | The unique identifier for the plugin (kebab-case, no spaces). |
### Optional Metadata Fields
| Field | Type | Description |
| -------------- | --------- | ------------------------------------------------------- |
| `version` | string | Semantic version number (e.g., `1.0.0`). |
| `displayName` | string | Human-readable name displayed in the UI. |
| `description` | string | A brief description. |
| `author` | object | Author information (`name`/`email`/`url`). |
| `homepage` | string | URL for documentation or homepage. |
| `repository` | string | URL for the source code repository. |
| `license` | string | SPDX license identifier (e.g., `MIT`, `Apache-2.0`). |
| `keywords` | string\[] | Tags for search and categorization. |
| `dependencies` | array | Other dependent plugins (marketplace can be specified). |
### Component Declaration Fields
The following fields are used to override conventional directories or declare components inline (as relative path strings, arrays, or object mappings):
| Field | Description |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `commands` | Command definitions. |
| `agents` | Path to the agent definition file. |
| `skills` | Path to the skills directory. |
| `outputStyles` | Output style definitions. |
| `workflowsPath` / `workflowsPaths` | Paths to workflow files. |
| `hooks` | Hook configuration (relative path to a JSON file or inline configuration). |
| `mcpServers` | MCP server configuration (relative path to a JSON file or inline configuration). |
| `userConfig` | Definitions for user-configurable options. |
| `settings` | Configurations merged when the plugin is enabled. Currently only the `agent` key is supported; other keys are ignored. |
## Conventional Directory Structure
If components are not explicitly declared in the manifest, the plugin automatically discovers them in the following conventional directories:
```text
plugin-name/
├── .qoder-plugin/
│ └── plugin.json # Recommended: manifest (optional)
├── commands/ # Command definitions (.md)
│ └── subdir/ # Supports nested directories
├── agents/ # Agent definitions (.md)
├── skills/ # Skills directory
│ └── skill-name/
│ └── SKILL.md
├── hooks/
│ └── hooks.json # Hook configuration
├── output-styles/ # Output style definitions
├── workflows/ # Workflow definitions
├── bin/ # Executables (added to PATH)
└── .mcp.json # MCP server configuration
```
> Compatible with `mcp.json` (without a leading dot) as a fallback for `.mcp.json`. If both exist, `.mcp.json` takes precedence, and they are not merged.
## Marketplace Manifest (marketplace.json)
A plugin marketplace describes a set of installable plugins via `marketplace.json`.
### Required Fields
| Field | Type | Description |
| --------- | ------ | ---------------------------------------------------------- |
| `name` | string | The name of the marketplace. |
| `owner` | object | Marketplace maintainer information (`name`/`email`/`url`). |
| `plugins` | array | Array of plugin entries. |
### Optional Fields
| Field | Type | Description |
| ------------------------------------- | --------- | ----------------------------------------------------------------- |
| `forceRemoveDeletedPlugins` | boolean | Automatically uninstall plugins removed from the marketplace. |
| `metadata.pluginRoot` | string | Base path relative to the plugin source. |
| `metadata.version` | string | Marketplace version. |
| `metadata.description` | string | Marketplace description. |
| `allowCrossMarketplaceDependenciesOn` | string\[] | Names of marketplaces allowed for cross-marketplace dependencies. |
### Plugin Entry Fields
| Field | Type | Description |
| ---------- | ------------- | --------------------------------------------------------------------- |
| `name` | string | Plugin name (must match `name` in `plugin.json`). |
| `source` | string/object | Plugin source (relative path, npm, git, github, url, etc.). |
| `category` | string | Category tag. |
| `tags` | string\[] | Search tags. |
| `strict` | boolean | Whether a manifest is required in the plugin folder (default `true`). |
## Management Commands
In an interactive session, use `/plugins` (alias `/plugin`); without a subcommand, it opens the plugin explorer:
| Subcommand | Arguments | Description |
| --------------------------------- | ---------- | --------------------------------------------------------------------------------------------------- |
| `install` (alias `i`) | `` | Install a plugin. |
| `uninstall` (alias `remove`/`rm`) | `` | Uninstall a plugin. |
| `enable` | `` | Enable a plugin. |
| `disable` | `` | Disable a plugin. |
| `update`\* | `` | Update a plugin. |
| `validate` | `` | Validate a plugin directory or `plugin.json`. |
| `marketplace` (alias `market`)\* | — | Manage plugin marketplaces, including `add `, `list`, `remove `, and `update [name]`. |
| `reload` | — | Reload all plugins. |
From the command line, use `qoder plugins` (alias `plugin`):
| Subcommand | Description |
| --------------------------------- | ------------------------------------------------------------------ |
| `list` | List installed plugins. |
| `install` (alias `i`) | Install a plugin from a marketplace or local directory. |
| `uninstall` (alias `remove`/`rm`) | Uninstall a plugin. |
| `enable` / `disable` | Enable / disable a plugin. |
| `update`\* | Update a plugin to the latest version from its source marketplace. |
| `validate` | Validate a plugin in a local directory. |
| `marketplace` (alias `mp`)\* | Manage plugin marketplaces. |
\* Commands marked with an asterisk are controlled by the plugin marketplace feature flag and are unavailable when disabled.
Startup parameter: `--plugin-dir ` appends additional plugin search directories.
## Security
These two settings are placed under the `security` group in `settings.json` (a restart is required after modification):
```json
{
"security": {
"blockGitExtensions": true,
"allowedExtensions": ["^https://github\\.com/my-org/"]
}
}
```
- `security.blockGitExtensions: true` can block installing/loading plugins from Git.
- `security.allowedExtensions` provides a regex allowlist for plugin sources; when non-empty, only matching sources are allowed (overrides `blockGitExtensions`).
## Next Steps
- Plugin usage guide: [Plugins](/cli/plugins-reference).
- Hooks reference: [Hooks reference](/cli/hooks-reference).
- MCP reference: [MCP reference](/cli/mcp-reference).
# Glossary
> Qoder CLI Core Concepts and Terminology
This page summarizes the core concepts and terminology used in the Qoder CLI documentation for quick reference.
## Product and Brand
| Term | Description |
| --------- | -------------------------------------------------- |
| Qoder | The AI-Native CLI brand for global users. |
| Qoder CLI | The full product name. |
| `qoder` | The command name entered by users in the terminal. |
## General Technical Terms
| Term | Description |
| -------------------- | --------------------------------------------------------------------------------------------------- |
| Terminal | The text-based interface environment where users interact with the CLI. |
| Subcommand | The action word following `qoder`, such as `login` and `commit`. |
| Flag | Command-line arguments, such as `--model` and `--resume`. |
| Environment Variable | System variables with the `QODER_` prefix used to configure CLI behavior. |
| TUI | Text User Interface, the rich interactive interface within the terminal. |
| Headless Mode | A non-interactive mode suitable for environments like CI/CD, which suppresses confirmation prompts. |
## Authentication
| Term | Description |
| ------------- | ----------------------------------------------------------------------------------- |
| Browser Login | The recommended sign-in method, which completes OAuth authentication via a browser. |
| Qoder PAT | Personal Access Token, suitable for CI/CD or browserless environments. |
## Models
| Term | Description |
| ---------------- | ------------------------------------------------------------------------------------------------ |
| Model Key | The unique identifier used to specify a model. |
| BYOK | Bring Your Own Key, allowing users to use custom models with their own API keys. |
| Default Models | The default tiered models provided, including Efficient, Auto, Performance, and Ultimate. |
| Custom Models | Custom models that support user-provided API keys. |
| Thinking Efforts | The thinking depth configured during model inference, such as low, medium, high, xhigh, and max. |
| Fast Mode | A fast mode offered by certain models that prioritizes response speed (`/fast`). |
| Context Window | The maximum amount of context the model can process at once. |
## Agent and Session
| Term | Description |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Agent | An AI assistant instance that executes tasks. |
| Subagent | An independent execution unit derived from the main agent, used for parallel processing of subtasks. |
| Session | A complete interactive session. |
| Memory | Persistent information remembered by the agent across sessions, retaining user preferences and project knowledge. |
| Memory File | Files that store memory, including user-level `~/.qoder/AGENTS.md`, project-level `AGENTS.md` and `AGENTS.local.md`, as well as rule files under `.qoder/rules/`. |
| Worktree | Git worktree isolation that allows the agent to work on an independent branch without affecting the main directory. |
| Compaction | Automatic compression of historical messages when conversations become too long, keeping them within the context window. |
| Plan Mode | A working mode where the agent formulates a plan first and executes it only after user confirmation. |
| Goal Mode | A working mode where the agent continuously executes tasks around a specified goal. |
| Dynamic Workflow | Dynamic workflows that use JavaScript scripts to orchestrate background tasks for multiple subagents. |
## Tools
| Term | Description |
| ---------- | --------------------------------------------------------------------------------------------------------------- |
| Tool | A capability unit callable by the agent, such as reading/writing files, executing commands, and searching code. |
| MCP | Model Context Protocol, a tool extension protocol that allows integration with third-party tools and services. |
| MCP Server | A server implementing the MCP protocol, supporting tool discovery and invocation. |
| RepoWiki | The `qoder wiki` command that generates structured Wiki documentation for a repository. |
## Permissions System
| Term | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Workspace Directory | The directory where the CLI is launched. |
| Additional Directory | Additional trusted directories added to the current session via `--add-dir` or `/add-dir`. |
| Permission Mode | The permission mode that sets the confirmation principles before tool execution. |
| Default Mode | The standard mode where safe reads and internal actions are executed automatically, while sensitive operations require individual confirmation. |
| Auto-accept Edits Mode | Automatically approves file edits, while shell commands still require confirmation. |
| Auto Mode | The AI automatically determines and approves safe operations. |
| Don't Ask Mode | Denies all operations that require confirmation. |
| YOLO Mode | Bypasses permissions and automatically approves all operations. |
## Plugins and Extensions
| Term | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------- |
| Plugin | An installable extension package that adds new skills, hooks, or MCP servers to the CLI. |
| Plugin Marketplace | The plugin marketplace for browsing and installing community or officially released plugins. |
| Slash Command | In-session shortcut commands starting with `/`. |
| Skill | Reusable professional capability templates invoked via `/skill-name`. |
| Conditional Skill | Skills that are activated only when specific file paths match. |
| Hook | Custom logic that executes automatically when specific events occur. |
| Hook Type | The execution method of a hook, supporting shell commands, HTTP requests, prompt injection, etc. |
| Hook Event | The timing that triggers a hook, such as before/after tool execution, or at the start/end of a session. |
## Configuration Files
| Term | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------- |
| User Settings | User-level configurations located at `~/.qoder/settings.json`, applying to all projects. |
| Project Settings | Project-level configurations located at `.qoder/settings.json`, shared along with the code repository. |
| Project Local Settings | Project local configurations located at `.qoder/settings.local.json`, applying only to the local machine. |
## Billing and Quota
| Term | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------- |
| Credits | The billing unit. |
| Plan | The account's current subscription plan (such as the Qoder Plan and plan credits in `/usage`). |
| Plan Tier | Subscription tiers: Community, Pro, and Teams. |
| Quota | The quota allowance, including used, remaining, and total amounts. |
| Price Factor | The multiplier for credits consumed by different models. |
| Add-on Credits | Add-on credit packages purchased separately in addition to the plan credits. |
| Org Resource Package | Organizational resource packages for unified allocation of credit resources across teams/organizations. |
## Integrations
| Term | Description |
| -------------- | -------------------------------------------------------------------------------------------------------------- |
| ACP | Agent Client Protocol, the communication protocol between the CLI and IDEs. |
| SDK | Software Development Kit, the development library provided by the CLI to support third-party integrations. |
| Cloud Mode | The `--remote` cloud execution mode, where tasks are hosted and run in cloud virtual machines. |
| Remote Control | Real-time control of locally running agents via mobile/web, enabling remote decision-making at critical nodes. |
## Next Steps
- Core concepts in detail: [How Task Execution Works](/cli/how-it-works).
- All configuration items: [Configurations, environment variables, and file paths](/cli/settings-reference).
# Installation and Upgrade Issues
> Troubleshoot common issues related to Qoder CLI installation, upgrades, PATH, and permissions.
This page summarizes common issues and solutions when installing or upgrading Qoder CLI. For installation steps, see [Installation and Upgrade](/cli/installation).
## command not found
If running `qoder` after installation results in a command not found error, it is usually because the directory containing the executable is not in your `PATH`.
- After a global installation via npm, ensure the global bin directory is added to your `PATH`:
```bash
npm config get prefix # Check the global installation prefix
# Add /bin to PATH
```
- After modifying your `PATH`, apply the changes: on Linux / macOS, after editing the shell configuration file (such as `~/.zshrc` or `~/.bashrc`), restart the terminal or run `source`; on Windows, after modifying system environment variables, restart the terminal.
- Verify the installation location:
```bash
# Linux / macOS
which qoder
```
```powershell
# Windows
where qoder # Command Prompt
Get-Command qoder # PowerShell
```
- If installation fails or no binary is available on Windows arm64 devices: this platform is not currently supported. See [Installation and Upgrade](/cli/installation).
## permission denied
- If you encounter permission errors during global installation, avoid forcing the installation with administrator privileges. It is recommended to change the npm Global Directory to a user-writable path and then reinstall.
- Using a Version Manager (such as nvm) to manage your runtime can avoid permission issues with system-level directories.
## Upgrade Failed or Version Not Updated
- First, run the built-in update command:
```shell
qoder update
```
- If the old version is still displayed after upgrading, first check which binary is currently being invoked (use `where qoder` on Windows):
```bash
which qoder
qoder --version
```
- If installed via multiple channels (e.g., using both npm and Homebrew), multiple `qoder` may exist, and the one appearing first in your `PATH` will be invoked. Uninstall the versions from redundant channels and keep only one.
- After cleanup, reinstall the latest version via the original channel: for script installations, use `curl -fsSL https://qoder.com/install | bash -s -- --force` to force a reinstall; for npm installations, use `npm install -g @qoder-ai/qodercli@latest`. See [Installation and Upgrade](/cli/installation) for details.
## Duplicate Installations / Multi-Version Conflicts
- List all matching executables to check for multiple copies: use `which -a qoder` on Linux / macOS, and `where qoder` (Command Prompt) or `Get-Command qoder -All` (PowerShell) on Windows.
- Keep only one installation channel and remove the others to avoid version confusion.
## Verify Installation
After installation is complete, run the following commands to confirm it is working:
```bash
qoder --version
qoder --help
```
If both commands produce normal output, the installation was successful.
## Next Steps
- Installation and upgrade guide: [Installation and Upgrade](/cli/installation).
- Network issues during download or installation: [Network, Proxy, and VPC Issues](/cli/troubleshoot-network).
- Sign-in issues: [Sign-in and Authentication Issues](/cli/troubleshoot-auth).
# Sign-in and Authentication Issues
> Resolve sign-in issues related to browser callbacks, accounts, tokens, and authentication networks.
This page helps troubleshoot common issues during sign-in and authentication. For sign-in methods, see [Sign-in and Authentication](/cli/authentication).
## Browser Callback Failure
Browser-based sign-in opens an authorization page and redirects back to the local environment upon completion. If it gets stuck waiting for the callback:
- Ensure the browser has successfully opened the authorization page and that authorization is complete.
- In environments without a graphical interface (CI, SSH sessions without `DISPLAY`, `BROWSER=www-browser`, etc.), Qoder CLI automatically skips launching the browser, and the sign-in screen itself prints a copyable Sign-in URL—just open that URL manually in a browser.
- Alternatively, select the option to use a Qoder Personal Access Token in the `/login` sign-in method, and paste the token directly to complete authentication.
- For long-term use on servers without a graphical interface, switch to Personal Access Token (PAT) authentication (see below).
- The local callback port may be blocked by a firewall or occupied by another process. Close the occupying process and try again.
- After completing authorization, manually switch back to the terminal and wait for the authentication status to refresh.
## Browserless Environment Login
In CI/CD environments or on servers without a browser, use PAT authentication:
1. Generate a Personal Access Token in [Qoder Integrations](https://qoder.com/account/integrations).
2. Provide it via an environment variable:
```shell
# Linux / macOS
export QODER_PERSONAL_ACCESS_TOKEN=""
```
```shell
# Windows (Command Prompt). Note: Do not add quotes, as CMD will store the quotes in the variable value.
set QODER_PERSONAL_ACCESS_TOKEN=
```
```shell
# Windows (PowerShell)
$env:QODER_PERSONAL_ACCESS_TOKEN=""
```
3. Once this variable is set, Qoder CLI will automatically use PAT authentication without requiring a browser.
## Invalid or Expired Token
- Ensure the value of `QODER_PERSONAL_ACCESS_TOKEN` is complete and correct, with no extra spaces or line breaks.
- When assigning a value using `set` in the Windows Command Prompt, do not use quotes; otherwise, the quotes will be included in the variable value. This is a common cause of "the value looks correct but authentication fails."
- If a token is revoked or expires, you must regenerate it and update the environment variable.
- If you updated the environment variable but are still running under the old identity: authentication reads the `QODER_PERSONAL_ACCESS_TOKEN` environment variable first, which takes precedence over the local credentials saved by `/login`; to use the `/login` credentials, you must clear this environment variable first.
- In CI environments, inject the token via secret variables to avoid committing it in plaintext to the repository.
## Account and Status
- Run `/status` to check the current sign-in identity and account status.
- If it shows you are not signed in, run `/login` to sign in again.
- To switch accounts, first run `/logout` and then `/login`.
- If you are currently authenticated via `QODER_PERSONAL_ACCESS_TOKEN`, you must clear this environment variable before running `/logout`; otherwise, the next startup will still automatically sign in with the old token, resulting in a "signed out but identity unchanged" behavior.
## Authentication Network Issues
If the sign-in request times out or the connection fails, it is usually a network/proxy issue:
- Ensure you can access the authentication service domain.
- Configure a proxy in restricted networks (see [Network, Proxy, and VPC Issues](/cli/troubleshoot-network)).
## Next Steps
- Sign-in and authentication guide: [Sign-in and Authentication](/cli/authentication).
- Network and proxy: [Network, Proxy, and VPC Issues](/cli/troubleshoot-network).
# Network, Proxy, and VPC Issues
> Resolve network issues related to connectivity, proxies, DNS, certificates, and VPC.
This page helps troubleshoot network connection issues with Qoder CLI. For network configuration, see [Network, Proxy, and VPC](/cli/network).
## Connection Timeouts or Failures
- Verify that your local machine can access the external network, and resolve and connect to the service domains.
- If you are on a corporate network or in a restricted environment, you typically need to configure a proxy (see below).
- For temporary network fluctuations, try again later; `general.retryFetchErrors` (enabled by default) automatically retries certain fetch errors.
## Proxy Configuration
Configure the proxy using standard environment variables:
```bash
export HTTPS_PROXY="http://proxy.example.com:8080"
export HTTP_PROXY="http://proxy.example.com:8080"
export NO_PROXY="localhost,127.0.0.1,.internal.example.com"
```
- `HTTPS_PROXY` / `HTTP_PROXY`: Used for HTTPS / HTTP requests, respectively.
- `NO_PROXY`: A comma-separated list of hosts that bypass the proxy.
- Both uppercase and lowercase are supported (both `HTTPS_PROXY` and `https_proxy` are recognized).
- Restart Qoder CLI after modifying environment variables for the changes to take effect.
## DNS Resolution Issues
- If domain resolution is abnormal, you can adjust the DNS resolution order via the `advanced.dnsResolutionOrder` configuration item.
- A restart is required for changes to take effect.
## Certificate Issues
- Corporate proxies often perform TLS Interception, requiring the Enterprise root certificate to be added to the System Trust Store.
- When encountering errors such as `unable to verify the first certificate`, use an environment variable to specify additional trusted certificates:
```shell
export NODE_EXTRA_CA_CERTS=/path/to/corp-root-ca.pem
```
You can also use `SSL_CERT_FILE` to specify the certificate file path. For details, see the certificate configuration section in [Network, Proxy, and VPC](/cli/network).
- Ensure the system time is correct—time skew will cause Certificate validation to fail.
## VPC / Private Deployment
- For the CN edition Private Deployment, you can specify the instance name via the `vpcInstanceName` configuration item, and public domains will be mapped to the corresponding per-instance private hosts.
- A restart is required for changes to take effect.
- Verify network reachability to the Private Gateway.
## Next Steps
- Network configuration guide: [Network, Proxy, and VPC](/cli/network).
- Sign-in network issues: [Sign-in and Authentication Issues](/cli/troubleshoot-auth).
# Configuration Not Applied
> Resolve issues related to configuration scope conflicts, override order, and formatting errors.
This page helps troubleshoot issues where `settings.json` configurations do not take effect as expected. For details on the configuration mechanism, see [Configuration Files and Application Order](/cli/settings) and [Configurations, environment variables, and file paths](/cli/settings-reference).
## Configuration Not in Effect
- **Restart required**: Some configuration items are marked as "restart required" and require restarting Qoder CLI to take effect after modification. Refer to [Configurations, environment variables, and file paths](/cli/settings-reference) to verify.
- **Overridden by higher priority**: Check if the same item is set at a higher priority level (Local Level > Project-Level > User Level), which overrides the lower priority setting.
- **Command-line override**: Configurations passed via `--settings` take precedence over all files and will override identically named items in the files.
## Review of Precedence Order
Configurations are merged from lowest to highest priority, with higher priorities overriding lower ones:
1. Built-in defaults
2. User Level (`~/.qoder/settings.json`)
3. Project-Level (`/.qoder/settings.json`)
4. Local Level (`/.qoder/settings.local.json`)
5. Command-line `--settings`
Objects are deeply merged by field; single values directly override existing ones; and certain arrays (such as disable/exclude lists) are union merged.
## Project Configuration Ignored
For security reasons, Project-Level and Local Level configurations are only applied when the current working directory is trusted. If `settings.json` within the project is completely ignored:
- Confirm that the current directory is trusted (`security.folderTrust.enabled` is enabled by default).
- When untrusted, only User Level configurations are loaded. Trust for the current working directory is determined by the **trust prompt at startup** (you can choose "this session only" or "remember", the latter of which is written to `settings.local.json`); you can also permanently trust frequently used directories using `permissions.trustDirectories` in the global settings.
- `/add-dir` and `--add-dir` only add **additional** trusted directories for the current session and cannot make an untrusted project directory trusted.
## Format Errors
- Configuration files are in JSON format, allowing `//` and `/* */` comments (which are stripped before parsing). Common errors include trailing commas, mismatched quotes, and unclosed brackets.
- The BOM at the beginning of the file is automatically ignored, but it is still recommended to save the file as UTF-8 without BOM.
- Use your editor and JSON Schema (`schemas/settings.schema.json`) for validation and completion.
- Fields must be placed under the correct group (e.g., `ui.theme` instead of the top-level `theme`).
- Use the `/settings` panel to view and modify settings to avoid manual formatting errors.
## Verify Current Configuration
- Run `/settings` to view the currently applied configuration items.
- Troubleshoot layer by layer: temporarily remove Local Level/Project-Level files to identify which layer introduced the issue.
## Next Step
- Configuration mechanism: [Configuration Files and Application Order](/cli/settings).
- Full configuration reference: [Configurations, environment variables, and file paths](/cli/settings-reference).
- Loading issues (Memory, Skills, and Agent not loaded): [Memory, Skills, and Agent not loaded](/cli/troubleshoot-loading).
# Hooks, MCP, and plugin issues
> Troubleshoot connection timeouts, authentication failures, untriggered Hooks, and extension loading issues.
This page helps troubleshoot issues related to Hooks, MCP servers, and plugins.
## First Checks
Before diving into specific components, rule out the two most common causes:
- **Directory Trust**: Untrusted workspaces will not load project-level settings, Hooks, MCP servers, and project-level Agents (Hooks are directly blocked in interactive sessions). When entering a directory for the first time, a trust prompt appears, allowing you to choose "this session only" or "remember" (written to `settings.local.json`). You can also use `permissions.trustDirectories` to permanently trust frequently used directories. See [Permissions](/cli/permissions).
- **Reload After Configuration Changes**: Most extensions support hot reload, which is faster than restarting—`/mcp reload`, `/plugins reload`, `/skills reload`, `/agents reload`. However, configuration items marked as "requires restart" still require restarting the CLI.
## Hooks Issues
When a Hook is not triggered or behaves abnormally:
- **Events and Matching**: Ensure the event name bound to the Hook is correct, and that `matcher` can match the target (empty or `*` matches all, exact values, `|` for multiple values, or regex).
- **Exit Codes**: `command` type Hooks use exit codes to control the flow—`0` for success, `2` to block (stderr is fed back to the Agent), and others for non-blocking errors. If a Hook unexpectedly blocks an operation, check if it returned `2`.
- **Input Parsing**: Hooks receive JSON from stdin (including `session_id`, `cwd`, `hook_event_name`, etc.). Ensure the script reads it correctly.
- **Executable Permissions**: The script pointed to by `command` must have executable permissions and the correct path.
- Use `/hooks` to view registered Hooks.
- For the complete reference, see [Hooks reference](/cli/hooks-reference).
## MCP Server Issues
When an MCP server is not connected or tools are unavailable:
- Use `/mcp` to check the server connection status.
- **Commands and Paths**: For stdio type, ensure `command`, `args`, and `cwd` are correct, and the server can start independently.
- **Project-Level Approval**: Project-level MCP servers require individual approval by default. Use `mcp.enableAllProjectMcpServers` or `mcp.enabledProjectMcpServers` to approve them.
- **Allowlist Restrictions**: Check if it has been filtered out by `mcp.allowed` / `mcp.excluded`, `--allowed-mcp-server-names`, or `--strict-mcp-config`.
- **Authentication**: For HTTP/SSE types, ensure the authentication information in `headers` is correct.
- **Timeouts**: If the connection is slow, adjust the `timeout` field.
- MCP configuration items are marked as "requires restart". After modification, try `/mcp reload` first; if it still doesn't take effect, restart.
- For the complete reference, see [MCP reference](/cli/mcp-reference).
## Plugin Issues
When a plugin is not loaded or components are missing:
- Use `/plugins` to view installed plugins.
- **Manifest**: The manifest is located at `.qoder-plugin/plugin.json` (can be omitted); if declared, ensure `name` is valid (kebab-case, no spaces).
- **Directory Structure**: Components must be located in the agreed directories (`commands/`, `agents/`, `skills/`, `hooks/hooks.json`, `.mcp.json`, etc.), or their paths must be explicitly declared in the manifest.
- **Security Restrictions**: When `security.blockGitExtensions` is true, loading plugins from Git is blocked; when `security.allowedExtensions` is not empty, only matching sources are allowed.
- For the complete reference, see [Plugin Reference](/cli/plugins-reference).
## Next Steps
- Hooks reference: [Hooks reference](/cli/hooks-reference).
- MCP reference: [MCP reference](/cli/mcp-reference).
- Plugin reference: [Plugin Reference](/cli/plugins-reference).
- Loading issues: [Memory, Skills, and Agent not loaded](/cli/troubleshoot-loading).
# Memory, Skills, and Agent not loaded
> Resolve issues where Memory, Skills, and Agents are not loaded due to file path or naming errors, priority overrides, or the need to reload.
This page helps troubleshoot issues where project instructions (memory), skills, and Agents are not loaded as expected.
## Memory / project instructions not loaded
When the project instructions file (default `AGENTS.md`) is not loaded into the context:
- **File name**: Ensure the file name matches the `context.fileName` configuration (default `AGENTS.md`).
- **Discovery boundary**: Upward search stops when it encounters a directory with `context.memoryBoundaryMarkers` (default `.git`). Files outside this boundary will not be discovered.
- **Additional directories**: By default, only the current directory is scanned. To load memory from additional trusted directories, enable `context.loadMemoryFromIncludeDirectories`.
- **Discovery limit**: `context.discoveryMaxDirs` (default 200) limits the number of directories searched, which may be reached in very large repositories.
- **Folder Trust**: Project content will not be loaded from untrusted directories.
- Use `/memory` to view the currently loaded memory sources.
## Skills not loaded
- Use `/skills` to view the list of loaded skills.
- **Directory structure**: Skills must be located in `skills//SKILL.md`. Ensure the directory hierarchy and file names are correct.
- **Source Priority**: The source priority for skills is built-in \< plugins \< project-level \< user-level. When names conflict, higher priority overrides lower priority.
- **Conditional Skill**: Activated only when the file path matches; otherwise, it does not appear.
- **Feature flag**: `/skills` requires skills support and administrator permissions to be enabled.
## Agent not loaded
- Use `/agents` to view the loaded Agents.
- Ensure the Agent definition file location and format are correct (definition files under the `agents/` directory).
- Check if `agents.overrides` has disabled the target Agent.
- Additional definitions loaded via `--agents` are valid for this session only.
## Reload
- After modifying definitions, reload by object: use `/memory` for memory, `/skills reload` for skills, and `/agents reload` for Agents; use `/commands` for custom commands.
- If the above methods do not work, restart Qoder CLI; some loading-related configurations are marked as "requires restart" and require a restart after modification.
## Next steps
- Context and memory mechanisms: [How Memory Works](/cli/how-memory-works), [Memory](/cli/memory).
- Extension loading issues: [Hooks, MCP, and plugin issues](/cli/troubleshoot-extensions).
- Configuration issues: [Configuration not applied](/cli/troubleshoot-config).
# Performance, Context, and Long Session Issues
> Resolve performance issues such as high CPU/memory usage, lag, and context pressure.
This page helps troubleshoot issues such as Qoder CLI lagging, high resource usage, or high context pressure.
## High Context Pressure / Frequent Compaction
When a conversation gets too long and the context approaches the context window limit, automatic compaction is triggered, which may slow down responses:
- Use `/compact` to proactively compact the context and free up space.
- Use `/context` to check the current context usage.
- Break down complex or long tasks into multiple shorter sessions, and use `/new` to start a new session.
- Use `model.maxSessionTurns` to limit the number of turns retained in a session (set `-1` for unlimited).
- Leverage subagents to isolate large tasks and prevent the main context from bloating.
## High Memory Usage
- `advanced.autoConfigureMemory` (enabled by default) automatically configures the Node.js memory limit.
- Use `ui.showMemoryUsage` to display memory usage in the interface for monitoring.
- In extremely large repositories, memory discovery is constrained by `context.discoveryMaxDirs` (default 200); narrow the working directory scope if necessary.
## High CPU Usage / Rendering Lag
Tuning options related to interface rendering (most are marked as "requires restart"):
- `ui.terminalBuffer`, `ui.renderProcess`: Terminal buffer and render process architecture.
- `ui.useAlternateBuffer` + `ui.incrementalRendering`: Incremental rendering reduces flickering (only supported when the alternate buffer is enabled).
- On low-performance terminals, you can disable dynamic elements such as `ui.showSpinner` and `ui.loadingPhrases`.
## Slow Tool Execution
- **Search**: Ensure `tools.useRipgrep` is enabled (default) for faster content search.
- **Shell Timeout**: `tools.shell.inactivityTimeout` (default 300 seconds) controls the timeout for no output; increase it appropriately for long-running commands.
- **MCP First-Turn Overhead**: When connecting to multiple MCP servers, enable Lazy Loading (`mcp.lazyLoad` or `QODER_MCP_LAZY=1`) to reduce first-turn token and loading overhead.
## Slow Startup
- Reduce unnecessary MCP servers and plugins, or use Lazy Loading.
- Narrow the memory discovery scope to avoid starting in extremely large directory trees.
## Next Steps
- Context mechanism: [How Memory Works](/cli/how-memory-works).
- Full configuration reference: [Configurations, environment variables, and file paths](/cli/settings-reference).
- Error messages and FAQ: [Error messages and FAQ](/cli/troubleshoot-faq).
# Error messages and FAQ
> Common error messages, causes, and solutions, as well as frequently asked questions.
This page summarizes the meanings and solutions for common error messages, along with some frequently asked questions. For more specific troubleshooting, refer to the dedicated troubleshooting pages.
## Common Errors
### fetch failed / Request failed
Network requests fail, usually due to network or proxy issues.
- Check network connectivity and proxy configuration. See [Network, Proxy, and VPC Issues](/cli/troubleshoot-network).
- `general.retryFetchErrors` (enabled by default) automatically retries some of these errors.
### Unauthenticated / Sign-in required
You are not currently signed in, or your credentials have expired.
- Run `/login` to sign in again, or set `QODER_PERSONAL_ACCESS_TOKEN`.
- See [Sign-in and Authentication Issues](/cli/troubleshoot-auth) for details.
### command not found (command not found: qoder)
`qoder` is not in `PATH`. See [Installation and Upgrade Issues](/cli/troubleshoot-install).
### Permission Denied / Action Blocked
Tool calls are blocked by the permissions system or a Hook.
- Use `/permissions` to view the current permission mode and rules, and adjust them if necessary. You can also press Shift+Tab to switch permission modes.
- If blocked by a Hook (exit code `2`), check the feedback message. See [Hooks, MCP, and plugin issues](/cli/troubleshoot-extensions).
### Configuration not in effect
The configuration is overridden by a higher-priority source, requires a restart, or has formatting errors. See [Configuration not applied](/cli/troubleshoot-config).
## Frequently Asked Questions
### How to check the version?
```bash
qoder --version
```
### How to run non-interactively in scripts?
Use `--print` (`-p`), which can be combined with `--output-format json` for easier programmatic consumption. See [Run in Scripts](/cli/run-in-scripts).
### How to resume the previous session?
Use `qoder --continue` (`-c`) to resume the most recent session, or `--resume` (`-r`) to select a historical session. See [session management](/cli/sessions).
### How to switch models?
Use `-m ` from the command line, or `/model` during an interactive session. See [Select model and reasoning effort](/cli/custom-models).
### How to roll back to previous code or conversation?
Use `/rewind` or the Checkpoint feature to restore. See [Undo and Restore](/cli/undo-restore).
### How to view usage and quota?
Use `/usage` to view usage statistics. See [Usage and Quota](/cli/usage).
### What to do when the context window is almost full?
Use `/compact` to proactively compress the context, or start a new session. See [Performance, Context, and Long Session Issues](/cli/troubleshoot-performance).
## Getting More Help
- Run `/help` in an interactive session to view help, or `/docs` to open the documentation.
- Use `/feedback` to submit feedback.
- Enable `--debug` (`-d`) to get debug logs for troubleshooting.
## Next Steps
- Installation issues: [Installation and Upgrade Issues](/cli/troubleshoot-install).
- Sign-in issues: [Sign-in and Authentication Issues](/cli/troubleshoot-auth).
- Network issues: [Network, Proxy, and VPC Issues](/cli/troubleshoot-network).
- Performance issues: [Performance, Context, and Long Session Issues](/cli/troubleshoot-performance).
- Loading issues: [Memory, Skills, and Agent not loaded](/cli/troubleshoot-loading).
- Configuration issues: [Configuration not applied](/cli/troubleshoot-config).
- Extension issues: [Hooks, MCP, and plugin issues](/cli/troubleshoot-extensions).
# Overview
Qoder Agent SDK lets a TypeScript or Python application run Qoder as a coding agent. Instead of returning only generated text, the agent can inspect a project, use approved tools, edit files, run commands, and report a structured result.
The SDK is suitable for adding agentic coding capabilities to a script, service, CI job, developer tool, or internal workflow without automating an interactive terminal.
## SDK and qodercli responsibilities
The SDK is the application-facing API. `qodercli` is the agent runtime that plans the task, communicates with the model, and executes tools in the target environment.
```text
TypeScript or Python application
|
| Qoder Agent SDK
| prompts, options, events, controls
v
qodercli
|
+-- Qoder model service
+-- files, commands, MCP tools, and subagents
```
Published SDK packages include a compatible qodercli runtime for supported platforms, so normal installations do not require a separate CLI setup. Applications can also point the SDK to a specific qodercli executable when the runtime is managed separately.
For the detailed startup, communication, and agent loop, see [How it works](/cli/sdk/how-it-works).
## Choose an SDK
Use the same language as the application hosting the Agent.
| | TypeScript | Python |
| ------------------- | -------------------------------- | ------------------------------------- |
| Package | `@qoder-ai/qoder-agent-sdk` | `qoder-agent-sdk` |
| Runtime requirement | Node.js 18+ | Python 3.10+ |
| One-off tasks | `query()` | `query()` |
| Multi-turn sessions | Async message input to `query()` | `QoderSDKClient` |
| Output | Async stream of typed messages | Async stream of typed message objects |
```bash TypeScript
npm install @qoder-ai/qoder-agent-sdk
```
```bash Python
pip install qoder-agent-sdk
```
See [Quick Start](/cli/sdk/quick-start) for complete, runnable examples in both languages.
## Programming model
A typical integration has four parts:
1. **Describe the task.** Send a prompt and set the working directory, model, system prompt, and turn limits as needed.
2. **Set boundaries.** Select allowed tools and a permission mode, or provide a callback for decisions that need application approval.
3. **Consume the message stream.** Handle assistant content, tool activity, progress events, and the final `result` message.
4. **Control the session when needed.** Long-lived integrations can send follow-up messages, interrupt work, change selected runtime settings, or query session state.
For a one-off task, use `query()` with a string prompt. For a conversation in which the next input depends on earlier output, use the language-specific multi-turn form shown in [Input Modes](/cli/sdk/input-modes).
## Configurable capabilities
| Area | Application capability |
| ------------------ | ------------------------------------------------------------------------------------------- |
| Input and output | One-off or multi-turn input, structured messages, and partial streaming events |
| Tools | Built-in file and command tools, custom tools, and external or in-process MCP servers |
| Agent behavior | System prompts, models, skills, plugins, reusable agent definitions, and subagents |
| Safety and control | Tool allowlists, permission modes, approval callbacks, hooks, interruption, and turn limits |
| Session management | Working directory, persistent sessions, resume, checkpoints, usage, and context information |
The [SDK References](/cli/sdk/references) page maps common concepts to each language's API.
## Execution boundaries
An agent can make real changes. Its working directory, tools, credentials, and permission policy are part of the application's security boundary.
- The SDK-to-qodercli channel is local by default, but qodercli communicates with the Qoder model service. Prompts and the context needed for inference can be sent to that service.
- File writes and commands run in the environment where qodercli is started. Set `cwd` deliberately and use [Permissions](/cli/sdk/permissions) to limit actions.
- The model does not access files or run commands directly. It requests tool calls, and qodercli validates and executes them under the configured policy.
- Permission-bypass modes are intended only for environments with an appropriate external isolation boundary.
## Next steps
- [Quick Start](/cli/sdk/quick-start) — install, authenticate, and run the first task
- [How it works](/cli/sdk/how-it-works) — understand SDK communication and the qodercli agent loop
- [Input Modes](/cli/sdk/input-modes) — choose one-off or multi-turn input
- [Permissions](/cli/sdk/permissions) — control tool access and approvals
- [SDK References](/cli/sdk/references) — find TypeScript and Python APIs
# Quick Start
Qoder Agent SDK lets you call Qoder AI capabilities from TypeScript or Python—reading and writing files, searching code, running commands, and more—embedding an AI agent into your app or script with just a few lines of code.
## Prerequisites
- TypeScript: Node.js 18+
- Python: Python 3.10+
## Install
```bash TypeScript
npm install @qoder-ai/qoder-agent-sdk
```
```bash Python
pip install qoder-agent-sdk
```
## Authentication
The SDK authenticates via a Personal Access Token (PAT), ideal for scripts, CI pipelines, and third-party integration scenarios.
Generate a PAT at [qoder.com/account/integrations](https://qoder.com/account/integrations) (copy it immediately — the value cannot be retrieved again after the page is closed). For full steps, custom environment variables, and reusing local `qodercli` credentials, see [SDK Authentication](/cli/sdk/authentication).
Once you have a PAT, set the environment variable first:
```bash TypeScript
export QODER_PERSONAL_ACCESS_TOKEN=""
node agent.mjs
```
```bash Python
export QODER_PERSONAL_ACCESS_TOKEN=""
python agent.py
```
Then configure authentication with `accessTokenFromEnv()` (TypeScript) / `access_token_from_env()` (Python):
```typescript TypeScript
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
const stream = query({
prompt: 'Hello',
options: {
auth: accessTokenFromEnv(),
},
});
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, access_token_from_env, query
options = QoderAgentOptions(auth=access_token_from_env())
async for message in query(prompt="Hello", options=options):
print(message)
```
The SDK reads this environment variable before starting qodercli and writes the parsed access token into a one-time auth payload. You typically don't need to pass the PAT via the `env` option; if `options.env` is explicitly provided, the SDK reads the same-named variable from it first.
> **Security Note**: Do not hard-code PATs in your code repository. Inject them via environment variables or a secrets management service.
## Single-message and streaming input
Both SDKs use `query()` as the core entry point. When `prompt` is a string, one call submits one user message, and the SDK closes the session after the turn completes—ideal for one-off, stateless tasks.
To send multiple messages in the same session and choose the next step from a response, pass an async message stream to TypeScript `query()` or maintain a long-lived connection with Python `QoderSDKClient`. See [Input Modes](/cli/sdk/input-modes).
## Complete Example
Create `agent.mjs` (TypeScript) or `agent.py` (Python):
```typescript TypeScript
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
for await (const message of query({
prompt: 'Analyze the codebase, find functions without test coverage, and write unit tests for them.',
options: {
auth: accessTokenFromEnv(),
allowedTools: ['Read', 'Write', 'Edit', 'Glob', 'Grep', 'Bash'],
permissionMode: 'acceptEdits', // Auto-approve file edits
},
})) {
if (message.type === 'assistant') {
for (const block of message.message.content) {
if (block.type === 'text') {
console.log(block.text); // AI text response
} else if (block.type === 'tool_use') {
console.log(`Tool: ${block.name}`); // Tool being called
}
}
} else if (message.type === 'result') {
console.log(`Done: ${message.subtype}`); // Final result
}
}
```
```python Python
import anyio
from qoder_agent_sdk import (
AssistantMessage,
QoderAgentOptions,
ResultMessage,
TextBlock,
ToolUseBlock,
access_token_from_env,
query,
)
async def main():
options = QoderAgentOptions(
auth=access_token_from_env(),
allowed_tools=["Read", "Write", "Edit", "Glob", "Grep", "Bash"],
permission_mode="acceptEdits", # Auto-approve file edits
)
async for message in query(
prompt=(
"Analyze the codebase, find functions without test coverage, "
"and write unit tests for them."
),
options=options,
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text) # AI text response
elif isinstance(block, ToolUseBlock):
print(f"Tool: {block.name}") # Tool being called
elif isinstance(message, ResultMessage):
print(f"Done: {message.subtype}") # Final result
anyio.run(main)
```
Run it:
```bash TypeScript
node agent.mjs
```
```bash Python
python agent.py
```
The Agent will autonomously browse the project, find functions lacking test coverage, generate test files, and run them for verification.
## Next Steps
- [SDK Authentication](/cli/sdk/authentication) — PAT, environment variables, and auth error handling
- [Input Modes](/cli/sdk/input-modes) — Single-message and streaming input, multi-message sessions, and session closure
- [Approval and User Input](/cli/sdk/user-input) — Tool approval, permission modes, and `AskUserQuestion`
- [Streaming Output](/cli/sdk/streaming-output) — Receive incremental content in real time, typewriter effect
- [SDK References](/cli/sdk/references) — Complete SDK reference
# Common integration scenarios
> Choose an integration pattern for batch jobs, interactive tools, backend services, approval workflows, and domain extensions.
The integration pattern depends mainly on three questions: whether input continues after a task starts, whether tool actions require an external decision, and whether a session must survive process or host changes. This page maps common product shapes to the recommended TypeScript and Python entry points, capability combinations, and runtime boundaries.
## Quick selection
```text
Task
|
+-- One input is enough -----------> one-off query()
+-- Follow-up input is required ---> TypeScript async message stream
| Python QoderSDKClient
+-- Actions require approval ------> canUseTool / can_use_tool + Hooks
+-- Sessions cross service hosts --> sessionStore / session_store + resume
`-- Business systems are needed --> MCP tools, Skills, or custom Agents
```
| Product shape | Recommended entry point | Key capabilities |
| -------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------- |
| Batch script or CI job | `query()` with a string task | `cwd`, tool scope, non-interactive permissions, Result |
| Interactive developer tool | TypeScript async message stream; Python `QoderSDKClient` | streaming output, added input, interrupt, session ID |
| Backend API or job service | create or resume a session per task | service authentication, concurrency control, external session storage |
| Human-approved automation | `canUseTool` / `can_use_tool` | allow/deny rules, approval UI, Hooks |
| Domain workflow | MCP, Skills, Agents, Plugins | business tools, domain instructions, reusable extension packages |
## Batch scripts and CI
Code inspection, test generation, migration reports, and documentation tasks often need one clear input and one final result. Call `query()` with a string and let the session end when the task completes.
```text
CI job or scheduled task
|
v
query("complete task")
|
+-- structured messages and tool activity
`-- Result: success, failure, or interruption
```
Recommended configuration:
- Use a PAT or Service Account authentication method intended for automation instead of a developer workstation sign-in.
- Set `cwd` explicitly so file and command operations stay in the job workspace.
- For reporting tasks, expose only read-oriented tools such as `Read`, `Glob`, and `Grep`. Add `Edit`, `Write`, or `Bash` only when changes are required.
- Background jobs cannot open a confirmation UI. Combine explicit allow/deny rules with `dontAsk` so unapproved actions fail closed. `acceptEdits` fits jobs that may modify a controlled workspace.
- Consume the stream through the Result and classify the outcome with `subtype`, `errors`, and `error_code` when available.
Skipping all permission checks is appropriate only when containers, disposable workspaces, or equivalent controls already isolate the task. See [Permissions](/cli/sdk/permissions) and [Error handling and error codes](/cli/sdk/errors).
## Interactive developer tools
Chat-based coding assistants, IDE features, and internal engineering portals need to accept more input after a task starts and display Agent text, tool activity, and status as they arrive.
- **TypeScript**: pass an `AsyncIterable` to `query()`.
- **Python**: create a session with `QoderSDKClient`, send messages with `query()`, and receive each turn with `receive_response()`.
- Drive interface updates from streaming events and use `interrupt()` to stop the active turn.
- Store the `session_id` that belongs to each product conversation. Use `resume` to continue it or fork when the original branch must remain unchanged.
- Assign an explicit delivery time to added input: change direction immediately, handle it at the next opportunity, or wait until the active turn finishes.
```text
Chat or IDE
| input, follow-ups, interrupt
v
long-lived session -----> streaming messages -----> interface
|
`--------------------> session_id
```
See [Input Modes](/cli/sdk/input-modes), [Streaming Output](/cli/sdk/streaming-output), and [Session Control](/cli/sdk/session-control).
## Backend APIs and job services
A backend service can turn an HTTP request, queue message, or scheduled job into an Agent session. Each active local session owns a qodercli process, so capacity planning must cover process count, model requests, file systems, and command execution resources.
```text
HTTP API / Queue
|
v
application service -----> Agent SDK -----> qodercli
| |
+-- session index or external store +-- workspace and commands
`-- logs, timeout, and cancellation `-- Qoder model service
```
A service integration commonly needs these constraints:
- The runtime must allow qodercli child processes and provide the task workspace, commands, and dependencies.
- Automated services use explicit credentials. Local sign-in is intended for developer workstations.
- Map requests to stable `session_id` values. A single host can use local sessions; multiple hosts, containers, or ephemeral disks should mirror sessions through `sessionStore` / `session_store`.
- Cross-host resume requires consistent project-directory semantics and project content on every eligible host.
- A streaming endpoint can forward Agent events to the caller. An asynchronous job can persist progress and the final Result.
- A timeout should call `interrupt()` or close the session while retaining useful error and process diagnostics.
See [SDK Authentication](/cli/sdk/authentication) and [External Session Storage](/cli/sdk/session-storage).
## Human-approved workflows
Code changes, command execution, release actions, or business-system writes may require a product interface, approval system, or policy service to decide. Permission control has a static boundary and a runtime decision path:
1. `tools` determines which tools are visible in the session.
2. `allowedTools` / `allowed_tools` and `disallowedTools` / `disallowed_tools` define preapproved and prohibited operations.
3. `canUseTool` / `can_use_tool` receives an unapproved tool request and returns allow or deny.
4. Hooks validate, audit, or alert before and after tool execution.
```text
Agent requests a tool
|
v
static rules ----deny----> denied tool result
|
approval
v
product UI / policy service
| allow | deny
v v
execute tool denied tool result
```
An approval view should present the tool name, important arguments, impact scope, and session context. Unattended jobs need a clear deny policy and timeout so a session cannot wait indefinitely. Approval callbacks and Hooks do not replace workspace isolation or least-privilege credentials.
See [Permissions](/cli/sdk/permissions) and [Hooks](/cli/sdk/hooks).
## Business tools and domain capabilities
Extensions let the Agent read business data, call internal systems, and reuse domain-specific working methods. Select the extension type by its purpose:
| Goal | Recommended capability | Suitable content |
| ----------------------------------- | ---------------------- | ----------------------------------------------------------- |
| Call a function in the host process | in-process MCP tool | data lookup, ticket actions, internal API wrappers |
| Connect an existing tool service | external MCP server | independently deployed standardized tool sets |
| Reuse operating instructions | Skills | team conventions, diagnostic procedures, delivery templates |
| Define a specialist role | Agents | code review, test analysis, migration planning |
| Distribute a set of extensions | Plugins | a package of Skills, Agents, MCP servers, and commands |
Tool inputs should use explicit structured fields, and responses should contain only the data required by the task. Business credentials should remain in the tool implementation or host service instead of being added to task text. Write operations should still pass through permission rules or approval callbacks.
See [Tools](/cli/sdk/tools), [MCP](/cli/sdk/mcp), [Agents](/cli/sdk/agents), [Skills](/cli/sdk/skills), and [Plugins](/cli/sdk/plugins).
## Production checklist
- **Runtime**: qodercli starts successfully, `cwd` points to the correct isolated workspace, and required commands and dependencies are available.
- **Authentication**: credentials come from environment variables or a secret manager, and logs and task text do not contain secrets.
- **Permissions**: the tool set follows least privilege, and background jobs do not depend on an unavailable confirmation interface.
- **Lifecycle**: the message stream is consumed through Result, with handling for timeout, interruption, process exit, and application shutdown.
- **Sessions**: `session_id` is stored when resume is required, and multi-host deployments use shared session storage.
- **Concurrency**: capacity accounts for active qodercli processes, workspaces, model requests, and tool resources.
- **Observability**: Result, tool activity, and necessary diagnostics are recorded while credentials and sensitive business data are filtered.
- **Versions**: use the runtime bundled with the SDK, or keep a separately configured qodercli executable compatible with the SDK version.
## Related documentation
- [Quick Start](/cli/sdk/quick-start) — run the first TypeScript or Python task
- [How it works](/cli/sdk/how-it-works) — understand processes, communication, and the Agent loop
- [SDK References](/cli/sdk/references) — find the exact API for each language
# How it works
Both SDKs run the Agent in a local qodercli process. The SDK exchanges JSONL messages and control requests with qodercli; qodercli calls the model service and executes approved tools.
## Architecture
```text
+------------------------- Application -----------------------------+
| TypeScript query() Python query() / SDK client |
| message parsing, callbacks, session controls |
+-------------------------------+-----------------------------------+
|
local JSONL over stdin/stdout
|
+-------------------------------v-----------------------------------+
| qodercli SDK mode |
| protocol + session -> agent loop -> permission + tool runner |
+--------------------------+----------------------+------------------+
| |
model requests local execution
| files / commands / MCP
v |
Qoder model service |
| |
+------ results -------+
```
One local runtime session is owned by one qodercli process. A string-based `query()` normally closes that session after the final result. Multi-turn APIs keep it alive while the application sends more input.
## Startup and handshake
The default local session starts in this order:
1. **Select the runtime.** The SDK uses an explicitly configured qodercli path when provided; otherwise it finds the compatible runtime shipped with the package or available in the environment.
2. **Start SDK mode.** The SDK launches qodercli with structured streaming input and output enabled. The process inherits the configured working directory and environment.
3. **Transfer authentication.** The SDK resolves the selected authentication method and provides qodercli with a temporary, one-time authentication payload instead of writing the credential into the message stream.
4. **Initialize capabilities.** Before sending the first task, the SDK and qodercli exchange an `initialize` control request. This registers SDK-provided hooks, agents, skills, and in-process MCP servers, then returns the runtime capabilities and available resources.
5. **Send the task.** After initialization succeeds, the SDK sends the first user message and begins yielding qodercli messages to the application.
Initialization failures are reported before the task runs, which helps distinguish configuration or authentication problems from an Agent failure.
## SDK and qodercli communication
For the default process transport, each protocol message is one JSON object on one line. The SDK reads and writes this JSON Lines (JSONL) stream; applications should use the typed SDK messages rather than parse process output directly.
```text
Application
|
| SDK writes to qodercli stdin
| user messages
| control requests and matching control responses
v
qodercli
|
| qodercli writes to stdout
| system, assistant, task, hook, and result messages
| partial stream events when enabled
| control requests and matching control responses
v
SDK message iterator
qodercli stderr --------------------> diagnostics (not protocol data)
```
There are two logical traffic types:
- **Agent messages** carry user input, assistant content, tool activity, progress, and the final result.
- **Control messages** perform initialization, interruption, session operations, permission decisions, hooks, and in-process MCP calls. A `request_id` pairs each control response with its request, so several operations can be in flight without confusing their results.
Either side can initiate a control request. The SDK can ask qodercli to interrupt the current turn; qodercli can ask the application to approve a tool or execute an SDK-hosted hook. The SDK routes inbound requests to the configured callback and returns the callback result to qodercli.
## The qodercli agent loop
qodercli repeatedly calls the model until the task finishes or reaches a configured limit. Tool results from one iteration become context for the next:
```text
user task + conversation history + instructions + tool definitions
|
v
build the next model request
|
v
stream model output
|
+------------+-------------+
| |
text/content tool call
| |
emit assistant events check policy and hooks
|
execute the tool
|
append the tool result to history
|
+------> next loop
no more tool calls
|
run completion hooks
|
emit final result
```
1. **Build context.** qodercli combines the task, conversation history, system instructions, workspace configuration, available tools, and relevant hook context.
2. **Ask the model.** Model output is streamed. Text can be surfaced immediately, while complete tool requests are sent to the execution pipeline.
3. **Authorize the action.** qodercli applies tool availability, allow/ask/deny rules, permission callbacks, and pre-tool hooks. A denied tool produces a tool result explaining the denial; it is not executed.
4. **Execute tools.** The runtime dispatches approved built-in tools, MCP tools, or subagents and captures their results. Independent tool calls can run concurrently when it is safe to do so.
5. **Continue with evidence.** Tool results are appended to the conversation, and the model receives another turn to inspect the outcome and choose the next action.
6. **Finish or stop.** The loop ends when the model has no more tool calls, a completion hook accepts the result, or a configured limit, interruption, cancellation, or error stops the task.
The model never opens a file or starts a process by itself. It proposes a tool call; qodercli is the component that decides whether and how to execute it.
## Tools, MCP, and subagents
qodercli presents the model with only the tools available to the session:
- **Built-in tools** read and edit files, search the project, run commands, and perform other local operations.
- **MCP tools** can come from an external MCP server or from an in-process server hosted by the SDK application. For an in-process server, qodercli sends an MCP control request to the SDK, the SDK calls the registered server, and the response returns over the same control channel.
- **Subagents** run a delegated task with their own prompt and context, usually with a narrower tool set. Their final output returns to the parent Agent as a tool result.
Tool results become model context and SDK events. Large results may be shortened in the conversation while the runtime preserves enough information for the Agent to continue safely.
## Context and session state
qodercli owns the live conversation state. The SDK owns the application callbacks and converts protocol objects into TypeScript or Python message types.
As a session grows, qodercli monitors its model context usage. When needed, it compacts older history into a smaller representation before the next model request. This keeps a long task moving without requiring the application to rebuild the prompt, although important details should still be stored in files or explicit session state instead of relying on unlimited conversation memory.
When session persistence is enabled, qodercli can store a transcript and resume it later. Resume and checkpoint behavior is described in [Session Storage](/cli/sdk/session-storage) and [Checkpoint](/cli/sdk/checkpoint).
## Completion, errors, and cancellation
Applications should keep consuming messages until they receive a `result` or the iterator raises an error.
- A successful or failed Agent turn is summarized by the final `result` message, including status and available usage information.
- `interrupt` asks qodercli to stop the active turn while keeping a long-lived session available where supported.
- Closing or aborting the SDK stream closes the transport. The process transport first attempts a graceful shutdown and escalates if qodercli does not exit.
- A process start failure, invalid protocol message, lost runtime, or initialization timeout is surfaced as an SDK error rather than an Agent result.
See [Session Control](/cli/sdk/session-control) for the public control APIs and [Cost and Usage](/cli/sdk/cost-usage) for usage fields.
## Security and data flow
The local process boundary does not mean the entire task stays on the local machine.
```text
local application <---- local protocol ----> qodercli
|
+----> Qoder model service
| task context and results
|
+----> local or configured tools
possible side effects
```
- Authentication is passed to qodercli separately from the JSONL message stream through a temporary payload that the SDK cleans up.
- qodercli sends the model service the task context needed for inference, which can include prompt content, file excerpts, and tool results.
- Tools execute in the qodercli environment and may read, write, or call other systems according to their configuration.
- `cwd`, tool allowlists, permission rules, hooks, sandboxing, and infrastructure isolation are complementary controls. Configure them according to the consequences of the task.
For approval patterns and permission modes, see [Permissions](/cli/sdk/permissions). For intercepting lifecycle events, see [Hooks](/cli/sdk/hooks).
## TypeScript and Python session shape
The runtime protocol is shared, but each SDK exposes a language-appropriate session API:
| Scenario | TypeScript | Python |
| ---------------------- | --------------------------------------------- | --------------------------------------------------- |
| One prompt, one result | `query({ prompt: string, ... })` | `query(prompt=..., options=...)` |
| Multiple user messages | Pass an async message iterable to `query()` | Connect a `QoderSDKClient` and call `query()` again |
| Read output | `for await` over discriminated message unions | `async for` over typed message objects |
| Runtime controls | Methods on the returned query stream | Methods on `QoderSDKClient` |
## Next steps
- [Quick Start](/cli/sdk/quick-start) — run the first TypeScript or Python task
- [Streaming Output](/cli/sdk/streaming-output) — handle full messages and partial events
- [Permissions](/cli/sdk/permissions) — design approval and tool policies
- [Tools](/cli/sdk/tools) — provide custom tools to the Agent
- [SDK References](/cli/sdk/references) — find the exact API for each language
# SDK Authentication
Every SDK session (TypeScript's `query()`, Python's `query()` / `QoderSDKClient`) must be configured with one authentication method. A session can only use one:
| Authentication method | Identity | Use case |
| -------------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------- |
| [Personal Access Token (PAT)](#use-a-pat) | A Qoder user | Scripts, CI, or host applications that need the user's permissions and data |
| [Service Account](#use-a-service-account) | An organization workload | Backend services, CI, and scheduled jobs that should not depend on a personal account |
| [Local qodercli session](#reuse-the-local-sign-in) | The currently signed-in user | A developer workstation that is already signed in to Qoder |
## Use a PAT
A PAT represents a Qoder user. Use it for automation that must access that user's permissions and data.
### Get a PAT
Create a PAT in [Qoder Account Integrations](https://qoder.com/account/integrations):
1. Sign in to Qoder.
2. Open **Account → Integrations**.
3. Choose the required permissions and expiry, then create the PAT.
4. Copy the generated value immediately. It cannot be viewed again after the page is closed.
Create separate PATs for local scripts, CI, and production so they can be rotated or revoked independently.
### Read a PAT from the environment
```bash
export QODER_PERSONAL_ACCESS_TOKEN=""
```
```typescript TypeScript
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Summarize the current workspace.',
options: {
auth: accessTokenFromEnv(),
},
});
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, access_token_from_env
options = QoderAgentOptions(auth=access_token_from_env())
```
The function reads `QODER_PERSONAL_ACCESS_TOKEN` by default. To use a custom variable name:
```typescript TypeScript
auth: accessTokenFromEnv('MY_QODER_PAT')
```
```python Python
auth = access_token_from_env("MY_QODER_PAT")
```
If `options.env` and the process environment contain the same variable, the SDK uses the value from `options.env`.
### Pass a PAT directly
When a trusted backend has already obtained a PAT, pass it directly:
```typescript TypeScript
import { accessToken, query } from '@qoder-ai/qoder-agent-sdk';
const token = await readTokenFromSecretManager();
const q = query({
prompt: 'List the most recently modified files.',
options: {
auth: accessToken(token),
},
});
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, access_token
token = read_token_from_secret_manager()
options = QoderAgentOptions(auth=access_token(token))
```
The SDK does not refresh PATs. After a PAT becomes invalid, obtain a valid PAT and create a new SDK session.
## Use a Service Account
Before you begin, ask a Qoder organization administrator to create a Service Account, grant the permissions your application needs, and generate a key. Store the key in a secret manager and provide it only to a trusted backend process or CI job.
### Pass a Service Account key directly
When a trusted backend has already read the key from a secret manager, pass it directly:
```typescript TypeScript
import { query, serviceAccount } from '@qoder-ai/qoder-agent-sdk';
// Get the Service Account key from the host's secret manager adapter.
const serviceAccountKey = await readSecret('qoder-service-account-key');
const q = query({
prompt: 'Explain the purpose of this project in one sentence.',
options: {
auth: serviceAccount({ serviceAccountKey }),
cwd: process.cwd(),
},
});
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, service_account
# Get the Service Account key from the host's secret manager adapter.
service_account_key = read_secret("qoder-service-account-key")
options = QoderAgentOptions(
auth=service_account(service_account_key=service_account_key)
)
```
The caller passes the Key into the session via `serviceAccount({ serviceAccountKey })` (TypeScript) / `service_account(service_account_key=...)` (Python). The SDK and qodercli obtain and refresh a short-lived Service Account Token (SAT) for the session.
```text
secret manager
|
| Service Account Key
v
caller reads the key
|
| serviceAccount({ serviceAccountKey })
v
SDK starts qodercli and obtains a short-lived SAT
|
`----> authenticate session requests with the SAT
```
The SDK uses the key and SAT for the current session. The caller provides the key again when creating a new session. Read the key from a secret manager, and keep key literals out of source code, browser bundles, mobile applications, logs, and test snapshots.
### Provide and refresh SATs from the host
If the host application embedding the SDK is responsible for exchanging SATs, use the fetch-callback form (TypeScript's `serviceAccount({ fetchServiceAccountToken })`, Python's `service_account(fetch_service_account_token=...)`). The Service Account Key stays in the host process, and qodercli receives SATs from the host callback.
The callback is implemented by the host. qodercli invokes it whenever it needs a SAT; on each request, the host calls the Token exchange API and returns the fresh SAT from the response to qodercli.
```text
qodercli
|
| request a SAT
v
fetchServiceAccountToken callback in the SDK host
|
| call Token exchange with the host-managed Service Account key
v
Qoder Token exchange
|
`----> return the short-lived SAT to qodercli
```
This complete example performs the exchange inside the host:
```typescript TypeScript
import {
query,
serviceAccount,
type ServiceAccountTokenResult,
} from '@qoder-ai/qoder-agent-sdk';
// Get the Service Account key from the host's secret manager adapter.
const serviceAccountKey = await readSecret('qoder-service-account-key');
// Example: select the scopes used for model listing and inference.
const serviceAccountScopes = ['models.read', 'chat.completions'];
async function fetchServiceAccountToken(): Promise {
const response = await fetch(
'https://openapi.qoder.sh/api/v1/serviceToken/exchange',
{
method: 'POST',
headers: {
Authorization: `Bearer ${serviceAccountKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
grant_type: 'client_credentials',
audience: 'qoder',
scope: serviceAccountScopes.join(' '),
ttl_seconds: 3600,
}),
},
);
if (!response.ok) {
throw new Error(`Unable to obtain a Qoder SAT: HTTP ${response.status}`);
}
const result = (await response.json()) as {
access_token: string;
expires_in?: number;
};
return {
token: result.access_token,
expiresAt:
result.expires_in === undefined
? undefined
: Date.now() + result.expires_in * 1000,
};
}
const q = query({
prompt: 'Summarize the current deployment configuration.',
options: {
auth: serviceAccount({ fetchServiceAccountToken }),
},
});
```
```python Python
import time
import httpx
from qoder_agent_sdk import (
QoderAgentOptions,
ServiceAccountTokenResult,
service_account,
)
# Get the Service Account key from the host's secret manager adapter.
service_account_key = read_secret("qoder-service-account-key")
# Example: select the scopes used for model listing and inference.
service_account_scopes = ("models.read", "chat.completions")
async def fetch_service_account_token() -> ServiceAccountTokenResult:
async with httpx.AsyncClient() as client:
response = await client.post(
"https://openapi.qoder.sh/api/v1/serviceToken/exchange",
headers={"Authorization": f"Bearer {service_account_key}"},
json={
"grant_type": "client_credentials",
"audience": "qoder",
"scope": " ".join(service_account_scopes),
"ttl_seconds": 3600,
},
)
response.raise_for_status()
result = response.json()
return ServiceAccountTokenResult(
token=result["access_token"],
expires_at=(
None
if result.get("expires_in") is None
else int(time.time()) + int(result["expires_in"])
),
)
options = QoderAgentOptions(
auth=service_account(
fetch_service_account_token=fetch_service_account_token
)
)
```
The scope and callback return value are configured as follows:
- When obtaining the SAT, enter the scopes that it should contain. For example, use `models.read chat.completions` to list models and call the inference API.
- Put the SAT returned by Token exchange in the callback result. You can also provide the SAT expiry.
- When a valid SAT cannot be obtained, return `null` (`None` in Python) or throw an exception so the current session fails explicitly.
## Reuse the local sign-in
If the workstation is already signed in through `qodercli`, the SDK can use the same session. This method is suitable for a developer workstation, not stateless CI or production services.
```typescript TypeScript
import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Summarize the current workspace.',
options: {
auth: qodercliAuth(),
},
});
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, qodercli_auth
options = QoderAgentOptions(auth=qodercli_auth())
```
## Authentication Failure Callback
When the remote side rejects the token, the token expires, or the CLI exits with an authentication error, use `onAuthExpired` (TypeScript) / `on_auth_expired` (Python) to trigger a re-login or token-exchange flow. It fires at most once per SDK session.
```python Python
from qoder_agent_sdk import QoderAgentOptions, access_token_from_env
def show_sign_in_required() -> None:
print("Authentication has expired. Please sign in again.")
options = QoderAgentOptions(
auth=access_token_from_env(),
on_auth_expired=show_sign_in_required,
)
```
The SDK does not automatically refresh PATs. After obtaining a new token, create a new SDK session with the new `auth` configuration.
## Authentication Errors
Python SDK authentication configuration errors raise exceptions with a `code`:
- Missing authentication configuration: `AuthNotConfiguredError`, with `code == "auth_not_configured"`.
- Missing PAT environment variable: `AuthAccessTokenEnvVarError`, with `code == "auth_access_token_env_var_not_configured"`.
- Missing Service Account Key environment variable: `AuthServiceAccountEnvVarError`, with `code == "auth_service_account_env_var_not_configured"`.
## Best Practices
- In production and CI, provide credentials through a secret manager; do not put credentials in source code.
- Do not write PATs, Service Account keys, or SATs to logs, error objects, or debug output.
- Configure a PAT or Service Account explicitly for automated environments instead of relying on the local `qodercli` sign-in.
- For user-facing applications, register the auth-expired callback to turn authentication failures into clear sign-in prompts.
- After updating or rotating credentials, create a new SDK session; do not reuse a session that has already failed authentication.
# Input Modes
Input mode determines one thing: **whether your application can keep sending messages to the Agent after a task starts**.
It does not distinguish between text, images, or other message content, and it does not determine whether responses are displayed incrementally. With either input mode, the SDK returns the Agent's responses as a message stream. To process those responses, see [Streaming Output](/cli/sdk/streaming-output).
Qoder Agent SDK provides two input modes:
| Input mode | TypeScript | Python | When to use it |
| -------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| Single-message input | `query({ prompt: string })` | `query(prompt=str)` | One-off tasks, batch jobs, and CI scripts |
| Streaming input | `query({ prompt: AsyncIterable })` | `QoderSDKClient` is recommended; a predetermined message stream can also be passed to `query()` | Chat interfaces, multi-message sessions, and tasks that need additional or revised instructions while running |
Choose between them by answering one question: **will your application need to send more messages after the task starts?**
- No. Use single-message input.
- Yes. For example, the user may follow up, or the application may choose the next step based on the Agent's response. Use streaming input.
## Single-message input
Passing a string to `query()` starts an independent task. After the task starts, you cannot append another user message to that call. The SDK ends the session when the task completes.
```typescript TypeScript
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
for await (const message of query({
prompt: 'Find functions in the current project that lack test coverage and report them.',
options: {
auth: accessTokenFromEnv(),
allowedTools: ['Read', 'Glob', 'Grep'],
},
})) {
if (message.type === 'result' && message.subtype === 'success') {
console.log(message.result);
}
}
```
```python Python
import anyio
from qoder_agent_sdk import (
QoderAgentOptions,
ResultMessage,
access_token_from_env,
query,
)
async def main():
options = QoderAgentOptions(
auth=access_token_from_env(),
allowed_tools=["Read", "Glob", "Grep"],
)
async for message in query(
prompt="Find functions in the current project that lack test coverage and report them.",
options=options,
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)
```
Single-message input does not disable tool approval. If the Agent needs to run a tool that has not been authorized, `canUseTool` / `can_use_tool` can still ask the user. You do not need to turn `prompt` into a message stream for that purpose. See [Approval and User Input](/cli/sdk/user-input).
## Streaming input
Streaming input lets your application keep sending messages after a task starts. In addition to multi-turn chat, it can supply new information, redirect a running task, or queue a message for later.
The recommended interface differs by SDK:
- **TypeScript**: pass an `AsyncIterable` to `query()`. The async iterator can continue to `yield` user messages supplied by a chat UI, message queue, or another event source.
- **Python**: use `QoderSDKClient` to keep the session open. Call `client.query(...)` to send a new message, then use `client.receive_response()` to receive that turn's response.
### Multi-message session
```typescript TypeScript
import {
accessTokenFromEnv,
query,
type SDKUserMessage,
} from '@qoder-ai/qoder-agent-sdk';
async function* messages(): AsyncGenerator {
yield {
type: 'user',
message: {
role: 'user',
content: [{ type: 'text', text: 'Check this codebase for security issues.' }],
},
parent_tool_use_id: null,
};
// A real application can wait here for a UI, message queue, or another event.
await new Promise((resolve) => setTimeout(resolve, 2_000));
yield {
type: 'user',
message: {
role: 'user',
content: [{ type: 'text', text: 'After the analysis, produce a brief report.' }],
},
parent_tool_use_id: null,
priority: 'later',
};
}
for await (const message of query({
prompt: messages(),
options: {
auth: accessTokenFromEnv(),
allowedTools: ['Read', 'Glob', 'Grep'],
},
})) {
if (message.type === 'result' && message.subtype === 'success') {
console.log(message.result);
}
}
```
```python Python
import anyio
from qoder_agent_sdk import (
AssistantMessage,
QoderAgentOptions,
QoderSDKClient,
ResultMessage,
TextBlock,
access_token_from_env,
)
async def main():
options = QoderAgentOptions(auth=access_token_from_env())
async with QoderSDKClient(options=options) as client:
await client.query("What is the capital of France?")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(f"Assistant: {block.text}")
# Choose the next message based on the previous response.
await client.query("What is the population of that city?")
async for message in client.receive_response():
if isinstance(message, ResultMessage):
print(f"Done: {message.subtype}")
anyio.run(main)
```
For TypeScript message fields, see [`SDKUserMessage`](/cli/sdk/references-typescript#sdkusermessage). In Python, each `receive_response()` call receives one turn. After receiving a `ResultMessage`, you can send the next message.
### Python async message stream boundary
Python `query()` also accepts `AsyncIterable[dict[str, Any]]`. If every message is known before the task starts, you can send them sequentially this way. The following fragment only shows the core async-message-stream pattern; see the complete example above for the creation of `query` and `options`:
```python Python
async def prompts():
yield {
"type": "user",
"message": {"role": "user", "content": "Inspect the authentication module."},
"parent_tool_use_id": None,
}
yield {
"type": "user",
"message": {"role": "user", "content": "Then summarize the findings."},
"parent_tool_use_id": None,
}
async for message in query(prompt=prompts(), options=options):
print(message)
```
Use this form only for messages prepared in advance. It cannot choose the next message from content the Agent has just returned, and it cannot call `interrupt()` or cancel a queued message. Interactive applications such as chat interfaces should use `QoderSDKClient`.
## Add input while the Agent is running
You can send another message while the Agent is responding. `priority` determines when the Agent processes it:
| Value | Behavior |
| ------- | -------------------------------------------------------------- |
| `now` | Stop the current response and process this message immediately |
| `next` | Default; process the message at the next suitable opportunity |
| `later` | Wait until the current response finishes |
Messages with the same priority are processed in send order. Use `priority: 'now'` to redirect the current work immediately. If you only want to stop the current response without sending a new message, use [Interrupt the current response](#interrupt-the-current-response).
Place the following snippets inside the TypeScript message generator or connected Python client session shown above:
```typescript TypeScript
yield {
type: 'user',
message: {
role: 'user',
content: [{ type: 'text', text: 'Stop the current direction and analyze only the failing tests.' }],
},
parent_tool_use_id: null,
priority: 'now',
};
```
```python Python
await client.query(
"Stop the current direction and analyze only the failing tests.",
priority="now",
)
```
### Add context without triggering a response
Sometimes you only want to provide background information without asking the Agent to respond immediately. Set `shouldQuery: false` in TypeScript or `should_query=False` in Python. The message is still added to the conversation, and `priority` determines when it takes effect.
```typescript TypeScript
yield {
type: 'user',
message: {
role: 'user',
content: [{ type: 'text', text: 'All subsequent suggestions must support Python 3.10.' }],
},
parent_tool_use_id: null,
shouldQuery: false,
};
```
```python Python
await client.query(
"All subsequent suggestions must support Python 3.10.",
should_query=False,
)
```
## Interrupt the current response
Call `interrupt()` to stop the Agent's current response without ending the session. You can continue sending messages afterward. In TypeScript, call it on the object returned by `query()`; Python requires `QoderSDKClient`.
```typescript TypeScript
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Inspect every file in the project.',
options: { auth: accessTokenFromEnv() },
});
const interruptTimer = setTimeout(() => {
void q.interrupt().catch(console.error);
}, 5_000);
try {
for await (const message of q) {
console.dir(message, { depth: null });
}
} finally {
clearTimeout(interruptTimer);
}
```
```python Python
import asyncio
from qoder_agent_sdk import QoderAgentOptions, QoderSDKClient, access_token_from_env
async def receive_turn(client):
return [message async for message in client.receive_response()]
async def main():
options = QoderAgentOptions(auth=access_token_from_env())
async with QoderSDKClient(options=options) as client:
await client.query("Inspect every file in the project.")
response_task = asyncio.create_task(receive_turn(client))
await asyncio.sleep(5)
await client.interrupt()
await response_task
asyncio.run(main())
```
`interrupt()` does not remove messages waiting in the queue. Cancel any queued message that is no longer needed. To end the entire session, call a close method or leave the `async with` block.
### Cancel a queued message
To cancel a message that has not started, first give it a UUID that is unique within the session. TypeScript uses the message's `uuid` field; Python uses the `message_uuid` argument:
The following fragments only show the cancellation operation and assume that `q` / `client` and the corresponding message UUID have already been created:
```typescript TypeScript
const cancelled = await q.cancelAsyncMessage(uuid);
```
```python Python
await client.query(
"Create a migration checklist after the current task finishes.",
priority="later",
message_uuid="optional-follow-up",
)
cancelled = await client.cancel_async_message("optional-follow-up")
```
Cancellation returns `true` / `True` when successful and `false` / `False` when the message does not exist or has already started. A message without a UUID cannot be cancelled individually. Do not reuse a UUID within the same session.
## End input and close the session
- **TypeScript**: the SDK ends a string-prompt session when the task finishes. With an async message stream, completion of the iterator means no more messages will be sent. To close the entire session early, use `AbortController` or call `q.close()`.
- **Python**: one-off `query()` calls end automatically. With `QoderSDKClient`, use `async with` to connect and disconnect automatically, or call `connect()` / `disconnect()` manually.
The following code only shows how a session ends and reuses the imports, `messages()`, and `options` definitions from the earlier examples:
### Close automatically
```typescript TypeScript
const q = query({
prompt: messages(),
options: { auth: accessTokenFromEnv() },
});
try {
for await (const message of q) {
console.dir(message, { depth: null });
}
} finally {
await q.close();
}
```
```python Python
async with QoderSDKClient(options=options) as client:
await client.query("Hello")
async for message in client.receive_response():
print(message)
# The connection closes automatically when the async with block exits.
```
### Close early in response to an external condition
```typescript TypeScript
const abortController = new AbortController();
const q = query({
prompt: 'Inspect every file in the project.',
options: { auth: accessTokenFromEnv(), abortController },
});
const taskTimeout = setTimeout(() => abortController.abort(), 5_000);
try {
for await (const message of q) {
console.dir(message, { depth: null });
}
} finally {
clearTimeout(taskTimeout);
}
```
```python Python
client = QoderSDKClient(options=options)
await client.connect()
try:
await client.query("Hello")
async for message in client.receive_response():
print(message)
finally:
await client.disconnect()
```
You cannot send another message after the session closes.
# Streaming Output
By default, a model's reply is delivered as a single complete message at the end of each turn. With streaming output enabled, the SDK pushes fine-grained incremental chunks as the model generates them — useful for typewriter effects, or for rendering reasoning and tool-invocation progress separately.
## Enable
Enable partial messages in options (`includePartialMessages` in TypeScript, `include_partial_messages` in Python):
```typescript TypeScript
import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Write a short analysis report',
options: {
auth: qodercliAuth(),
includePartialMessages: true,
},
});
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, access_token_from_env, query
options = QoderAgentOptions(
auth=access_token_from_env(),
include_partial_messages=True,
)
async for msg in query(prompt="Write a short analysis report", options=options):
...
```
## Typewriter effect
The model's text reply arrives as a sequence of incremental chunks; printing each chunk as it lands gives a typewriter effect:
```typescript TypeScript
for await (const msg of q) {
if (msg.type === 'stream_event') {
const delta = msg.event.delta;
if (delta?.type === 'text_delta') {
process.stdout.write(delta.text);
}
}
}
```
```python Python
import sys
from qoder_agent_sdk import StreamEvent
async for msg in query(prompt="...", options=options):
if isinstance(msg, StreamEvent):
delta = msg.event.get("delta")
if delta and delta.get("type") == "text_delta":
sys.stdout.write(delta["text"])
sys.stdout.flush()
```
## Reasoning
Reasoning-capable models emit "thinking" chunks before their final reply:
```typescript TypeScript
if (delta?.type === 'thinking_delta') {
process.stdout.write(delta.thinking);
}
```
```python Python
if isinstance(msg, StreamEvent):
delta = msg.event.get("delta")
if delta and delta.get("type") == "thinking_delta":
sys.stdout.write(delta["thinking"])
sys.stdout.flush()
```
## Tool invocation arguments
Tool-call arguments are also generated incrementally — for example, you can use this to render the file content the model is writing in real time:
```typescript TypeScript
if (delta?.type === 'input_json_delta') {
process.stdout.write(delta.partial_json);
}
```
```python Python
if isinstance(msg, StreamEvent):
delta = msg.event.get("delta")
if delta and delta.get("type") == "input_json_delta":
sys.stdout.write(delta["partial_json"])
sys.stdout.flush()
```
For the full event structure, see [SDK References](/cli/sdk/references).
# Approval and User Input
Two situations require user participation while the Agent is working:
1. The Agent wants to run a tool and needs the user to approve it.
2. The Agent lacks required information and needs the user to answer a question.
When the host application handles user interaction through `canUseTool` (`can_use_tool` in Python), both requests arrive through the same callback. Your application displays an approval prompt or question and returns the user's choice to the SDK.
| What the user sees | Typical tool | What the user provides | What the application returns |
| ---------------------- | ------------------------------- | ------------------------------- | ----------------------------------- |
| Tool approval | `Bash`, `Write`, or an MCP tool | Whether to allow this operation | The original or reviewed tool input |
| Clarification question | `AskUserQuestion` | The actual answer | `questions` and `answers` |
You can configure the callback with either a single-message or streaming `prompt`. A one-off `query()` can also display tool approvals and clarification questions.
## When canUseTool runs
After the Agent requests a tool, the SDK evaluates your permission configuration. One of three outcomes follows:
- Already allowed: the tool runs without calling `canUseTool`.
- Already denied: the tool is rejected without calling `canUseTool`.
- User approval required: the SDK calls `canUseTool` and waits for your application to allow or deny the request.
`AskUserQuestion` is different from an ordinary tool because it requires a real user answer. When `canUseTool` / `can_use_tool` is configured, the SDK calls the callback for an answer unless user interaction has been explicitly disabled.
Because the callback does not receive every tool call, do not use `canUseTool` as a complete tool-execution log. Use [hooks](/cli/sdk/hooks) to observe every tool call. See [Permission Control](/cli/sdk/permissions) for the permission evaluation order.
To let your application handle dynamic approval or `AskUserQuestion`, configure `canUseTool` / `can_use_tool`, or use an external permission prompt tool. If the runtime sends a permission request but the SDK has no corresponding callback, the SDK fails closed and reports an error; it never executes the tool automatically.
### Configure the callback
The following snippets only show callback configuration. `showApprovalDialog` / `show_approval_dialog` represents an approval UI implemented by the host application; it is not an SDK function. For a runnable terminal implementation, see the [complete example](#complete-example).
```typescript TypeScript
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
query({
prompt: 'Read the release configuration and generate a changelog. Ask before writing files.',
options: {
auth: accessTokenFromEnv(),
permissionMode: 'default',
allowedTools: ['Read'],
async canUseTool(toolName, input, context) {
const approved = await showApprovalDialog({
toolName,
input,
title: context.title,
description: context.description,
signal: context.signal,
});
if (!approved) {
return {
behavior: 'deny',
message: 'The user denied this operation.',
toolUseID: context.toolUseID,
};
}
return {
behavior: 'allow',
updatedInput: input,
toolUseID: context.toolUseID,
};
},
},
});
```
```python Python
from typing import Any
from qoder_agent_sdk import (
PermissionResultAllow,
PermissionResultDeny,
QoderAgentOptions,
ToolPermissionContext,
)
async def can_use_tool(
tool_name: str,
input_data: dict[str, Any],
context: ToolPermissionContext,
):
approved = await show_approval_dialog(
tool_name=tool_name,
input_data=input_data,
title=context.title,
description=context.description,
signal=context.signal,
)
if not approved:
return PermissionResultDeny(message="The user denied this operation.")
return PermissionResultAllow(updated_input=input_data)
options = QoderAgentOptions(
permission_mode="default",
allowed_tools=["Read"],
can_use_tool=can_use_tool,
)
```
In TypeScript, `context.signal` is an `AbortSignal`. In Python, it is `asyncio.Event | None`. If the task has been cancelled, close the approval UI and end the callback. The TypeScript example returns `toolUseID` to identify the specific tool call being handled.
Use `canUseTool` / `can_use_tool` when your application supplies the approval UI. If an external permission prompt tool already exists, use `permissionPromptToolName` / `permission_prompt_tool_name` instead. You cannot configure both approaches at the same time.
## Return approval results
### Allow once
To allow the tool to run, return its input:
```typescript TypeScript
return {
behavior: 'allow',
updatedInput: input,
toolUseID: context.toolUseID,
};
```
```python Python
return PermissionResultAllow(updated_input=input_data)
```
`updatedInput` / `updated_input` is the input the tool ultimately receives. You can return it unchanged, or remove unsafe flags, restrict a path, or modify another field before allowing the call. Validate any modified input against that tool's input format.
### Deny
When denying a call, include a short reason. The Agent can use it to choose another approach or explain why the operation was not performed:
```typescript TypeScript
return {
behavior: 'deny',
message: 'This command is not allowed in production.',
toolUseID: context.toolUseID,
};
```
```python Python
return PermissionResultDeny(
message="This command is not allowed in production.",
)
```
To stop the entire task immediately after the denial, set `interrupt: true` (`interrupt=True` in Python).
### Always allow for this session
`context.suggestions` may contain permission rules that the SDK recommends saving. When the user selects “Always allow for this session,” include those suggestions in the allow result:
```typescript TypeScript
return {
behavior: 'allow',
updatedInput: input,
updatedPermissions: context.suggestions,
toolUseID: context.toolUseID,
};
```
```python Python
return PermissionResultAllow(
updated_input=input_data,
updated_permissions=context.suggestions,
)
```
These rules can prevent the same type of operation from being requested again during the current session. For the complete `PermissionUpdate` type and custom rule construction, see [Update permissions during a session](/cli/sdk/permissions#updating-permissions-within-a-session-permissionupdate).
## How permission modes affect the callback
`permissionMode` / `permission_mode` sets the default tool-request behavior for the session. It affects whether the user sees an approval prompt and whether `canUseTool` is called. The following table assumes that `canUseTool` / `can_use_tool` is configured and that `AskUserQuestion` is visible in `tools`:
| Permission mode | Ordinary tools | `AskUserQuestion` |
| ---------------------------- | --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| `default` | Tools that need approval call the callback | Calls the callback for the user's answer |
| `acceptEdits` | Common file edits are allowed directly; other tools may still require approval | Calls the callback for the user's answer |
| `plan` | Does not perform actual modifications; approval may still be requested when needed | Can ask questions to clarify requirements or a plan |
| `auto` | The SDK automatically allows or denies some tools, so the callback is not guaranteed for every call | Calls the callback for the user's answer |
| `dontAsk` | Tools that were not pre-authorized are denied without prompting | The question is also denied, so the Agent cannot wait for an answer |
| `bypassPermissions` / `yolo` | Ordinary tools run without an approval prompt | Still calls the callback; the SDK cannot answer on the user's behalf |
Keep these constraints in mind:
- If `disallowedTools` / `disallowed_tools` or a deny rule blocks `AskUserQuestion`, the Agent cannot ask the user a question.
- If `tools` is set explicitly, include `AskUserQuestion`; otherwise the Agent cannot see the tool.
- Use `bypassPermissions` and `yolo` only in trusted environments. They skip approval for ordinary tools but do not answer questions for the user.
- To show every not-yet-authorized operation in your own approval UI, normally use `default` and do not add those tools to `allowedTools` / `allowed_tools`.
For the complete behavior and risks of every mode, see [Default policy: permissionMode](/cli/sdk/permissions#controlling-default-policy-permissionmode).
## Handle AskUserQuestion
`AskUserQuestion` asks a small number of structured questions before the Agent continues the current task—for example, to choose a target environment, implementation approach, or output format. It is not a new chat message. After the user answers, the Agent resumes the current task.
When `canUseTool` receives `toolName === 'AskUserQuestion'`, the callback's `input` has this runtime structure:
```typescript
type AskUserQuestionRuntimeInput = {
questions: Array<{
question: string;
header: string;
options: Array<{
label: string;
description: string;
preview?: string;
}>;
multiSelect?: boolean;
}>;
};
```
- A request contains 1–4 questions.
- Each question has a short `header` and 2–4 options.
- If `multiSelect` is `false` or omitted, the user can select one option. If it is `true`, the user can select multiple options.
- Your UI should also let the user enter an answer that is not one of the options.
- An option can include `preview`. In TypeScript, `toolConfig.askUserQuestion.previewFormat` specifies whether previews are interpreted as `markdown` or `html`. The Python SDK currently has no equivalent `tool_config` option.
> In a `canUseTool` callback, use the runtime `questions` / `answers` structure shown here, not singular `question` / `answer` fields.
### Return question answers
Return `behavior: 'allow'` when submitting answers. Here, `allow` means “accept these answers and continue the task.” Include both the questions and answers in `updatedInput`:
```typescript
{
behavior: 'allow',
updatedInput: {
questions: input.questions,
answers: {
'Which environment should receive the deployment?': 'Staging',
'Which checks should be enabled?': 'Type checking, Unit tests',
'Any other requirements?': 'Keep compatibility with Node.js 18',
},
},
}
```
Encode `answers` as follows:
- Each key must be the complete `question` text for the corresponding question.
- For a single selection, use the option's `label`. For a custom answer, use the text entered by the user.
- For multiple selections, join the labels into one string with `, `.
- If the user cancels the questions, return deny with a reason. Do not continue with invented or blank answers.
## Complete example
The following example handles both questions and ordinary tool approvals. A real application can replace terminal input with a dialog, web page, or approval service.
```typescript TypeScript
import { createInterface } from 'node:readline/promises';
import {
accessTokenFromEnv,
query,
type CanUseTool,
} from '@qoder-ai/qoder-agent-sdk';
type Question = {
question: string;
header: string;
options: Array<{ label: string; description: string }>;
multiSelect?: boolean;
};
const readline = createInterface({
input: process.stdin,
output: process.stdout,
});
function parseAnswer(raw: string, question: Question): string {
const indexes = raw
.split(',')
.map((part) => Number.parseInt(part.trim(), 10) - 1)
.filter((index) => index >= 0 && index < question.options.length);
if (indexes.length > 0) {
const selected = question.multiSelect ? indexes : indexes.slice(0, 1);
return selected.map((index) => question.options[index].label).join(', ');
}
return raw.trim();
}
async function readLine(
prompt: string,
signal: AbortSignal,
): Promise {
try {
return await readline.question(prompt, { signal });
} catch (error) {
if (
signal.aborted ||
(error instanceof Error && error.name === 'AbortError')
) {
return null;
}
throw error;
}
}
const canUseTool: CanUseTool = async (toolName, input, context) => {
if (context.signal.aborted) {
return {
behavior: 'deny',
message: 'The request was cancelled.',
toolUseID: context.toolUseID,
};
}
if (toolName === 'AskUserQuestion') {
const questions = (input.questions ?? []) as Question[];
const answers: Record = {};
for (const question of questions) {
console.log(`\n${question.header}: ${question.question}`);
question.options.forEach((option, index) => {
console.log(`${index + 1}. ${option.label} — ${option.description}`);
});
const hint = question.multiSelect
? 'Enter option numbers separated by commas, or a custom answer (/cancel to cancel): '
: 'Enter an option number or a custom answer (/cancel to cancel): ';
let answer = '';
while (!answer) {
const raw = await readLine(hint, context.signal);
if (raw === null || raw.trim() === '/cancel') {
return {
behavior: 'deny',
message: 'The user cancelled the questions.',
toolUseID: context.toolUseID,
};
}
answer = parseAnswer(raw, question);
if (!answer) {
console.log('An answer is required. Try again.');
}
}
answers[question.question] = answer;
}
return {
behavior: 'allow',
updatedInput: { questions, answers },
toolUseID: context.toolUseID,
};
}
const answer = await readLine(
`\nAllow ${toolName} with input ${JSON.stringify(input)}? [y/N] `,
context.signal,
);
if (answer === null) {
return {
behavior: 'deny',
message: 'The request was cancelled.',
toolUseID: context.toolUseID,
};
}
if (answer.trim().toLowerCase() !== 'y') {
return {
behavior: 'deny',
message: `The user denied ${toolName}.`,
toolUseID: context.toolUseID,
};
}
return {
behavior: 'allow',
updatedInput: input,
toolUseID: context.toolUseID,
};
};
try {
for await (const message of query({
prompt: 'Inspect the project and produce release notes. Ask me when the release target is unclear.',
options: {
auth: accessTokenFromEnv(),
tools: ['AskUserQuestion', 'Read', 'Write', 'Bash'],
allowedTools: ['Read'],
permissionMode: 'default',
canUseTool,
},
})) {
if (message.type === 'result') {
console.log(message.subtype);
}
}
} finally {
readline.close();
}
```
```python Python
from typing import Any
import anyio
from qoder_agent_sdk import (
PermissionResultAllow,
PermissionResultDeny,
QoderAgentOptions,
ResultMessage,
ToolPermissionContext,
access_token_from_env,
query,
)
def parse_answer(raw: str, question: dict[str, Any]) -> str:
indexes = []
for part in raw.split(","):
try:
index = int(part.strip()) - 1
except ValueError:
continue
if 0 <= index < len(question["options"]):
indexes.append(index)
if indexes:
selected = indexes if question.get("multiSelect") else indexes[:1]
return ", ".join(question["options"][index]["label"] for index in selected)
return raw.strip()
async def read_line(prompt: str) -> str:
return await anyio.to_thread.run_sync(input, prompt)
async def can_use_tool(
tool_name: str,
input_data: dict[str, Any],
context: ToolPermissionContext,
):
if context.signal is not None and context.signal.is_set():
return PermissionResultDeny(message="The request was cancelled.")
if tool_name == "AskUserQuestion":
questions = input_data.get("questions", [])
answers: dict[str, str] = {}
for question in questions:
print(f"\n{question['header']}: {question['question']}")
for index, option in enumerate(question["options"], start=1):
print(f"{index}. {option['label']} — {option['description']}")
hint = (
"Enter option numbers separated by commas, or a custom answer (/cancel to cancel): "
if question.get("multiSelect")
else "Enter an option number or a custom answer (/cancel to cancel): "
)
while True:
if context.signal is not None and context.signal.is_set():
return PermissionResultDeny(message="The request was cancelled.")
raw = await read_line(hint)
if context.signal is not None and context.signal.is_set():
return PermissionResultDeny(message="The request was cancelled.")
if raw.strip() == "/cancel":
return PermissionResultDeny(
message="The user cancelled the questions."
)
answer = parse_answer(raw, question)
if answer:
answers[question["question"]] = answer
break
print("An answer is required. Try again.")
return PermissionResultAllow(
updated_input={"questions": questions, "answers": answers}
)
answer = await read_line(
f"\nAllow {tool_name} with input {input_data}? [y/N] "
)
if context.signal is not None and context.signal.is_set():
return PermissionResultDeny(message="The request was cancelled.")
if answer.strip().lower() != "y":
return PermissionResultDeny(message=f"The user denied {tool_name}.")
return PermissionResultAllow(updated_input=input_data)
async def main():
options = QoderAgentOptions(
auth=access_token_from_env(),
tools=["AskUserQuestion", "Read", "Write", "Bash"],
allowed_tools=["Read"],
permission_mode="default",
can_use_tool=can_use_tool,
)
async for message in query(
prompt="Inspect the project and produce release notes. Ask me when the release target is unclear.",
options=options,
):
if isinstance(message, ResultMessage):
print(message.subtype)
anyio.run(main)
```
The Python terminal example uses blocking `input()`. After a task is cancelled, it cannot check `context.signal` until the current input call returns. A web or desktop application should not inherit this limitation: listen for `context.signal`, close the dialog immediately when it fires, and end the callback.
## Capability boundaries
| Requirement | Recommended capability | Why |
| ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| Confirm whether a tool should run | `canUseTool` / `can_use_tool` | Can allow, deny, or revise tool input first |
| Collect 1–4 short answers before the Agent continues | `AskUserQuestion` | The Agent supplies questions and options, then continues after the user answers |
| Let the user follow up, add long text, or redirect the task | [Streaming input](/cli/sdk/input-modes#streaming-input) | This is a new user message |
| Collect fixed fields, enforce strict validation, upload files, or display a complex form | [Custom tools](/cli/sdk/tools#custom-tools) | The application controls the data format and UI |
| Let an MCP server request form or authorization information | [MCP Elicitation](/cli/sdk/mcp#elicitation-server-requests-user-input) | These requests use `onElicitation` / `on_elicitation` |
| Record every tool call or apply a uniform tool interceptor | [Hooks](/cli/sdk/hooks) and [Permission Control](/cli/sdk/permissions) | `canUseTool` does not receive calls that were automatically allowed or denied |
Do not use `AskUserQuestion` as a replacement for multi-turn conversation. New messages initiated by the user should use streaming input. Do not use a normal text response in place of tool approval either, because the SDK requires an explicit allow or deny result.
# Session Control
By default the SDK starts a brand-new session on every call (TypeScript's `query()`) or connection (Python's `QoderSDKClient`). A few fields in options let you specify a session ID, resume a historical session, or fork an existing one.
## Concepts
A session corresponds to a persisted conversation history on the CLI side (including context, tool call records, compaction boundaries, etc.), identified by a UUID. The `init` system message contains the current `session_id`, which also serves as the anchor point for subsequent resume/fork operations.
The authentication in the examples below can be replaced with whichever method your project uses; see [SDK Authentication](/cli/sdk/authentication).
## Creating New Sessions
### Default
Without passing any session-related fields, a new session is created each time:
```typescript TypeScript
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Hello',
options: { auth: accessTokenFromEnv() },
});
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, QoderSDKClient, qodercli_auth
options = QoderAgentOptions(auth=qodercli_auth())
async with QoderSDKClient(options=options) as client:
await client.query("Hello")
async for msg in client.receive_response():
...
```
### Specifying a Session ID
Let the caller determine the session UUID (suitable when the host manages its own session index):
```typescript TypeScript
import { randomUUID } from 'node:crypto';
const sessionId = randomUUID();
const q = query({
prompt: 'Hello',
options: {
auth: accessTokenFromEnv(),
sessionId,
},
});
```
```python Python
import uuid
session_id = str(uuid.uuid4())
options = QoderAgentOptions(
auth=qodercli_auth(),
session_id=session_id,
)
async with QoderSDKClient(options=options) as client:
await client.query("Hello")
async for msg in client.receive_response():
...
```
## Resuming Sessions
### Resume by ID
```typescript TypeScript
const q = query({
prompt: 'Continue the previous conversation',
options: {
auth: accessTokenFromEnv(),
resume: 'previous-session-id',
},
});
```
```python Python
options = QoderAgentOptions(
auth=qodercli_auth(),
resume="previous-session-id",
)
async with QoderSDKClient(options=options) as client:
await client.query("Continue the previous conversation")
async for msg in client.receive_response():
...
```
### Resume the Most Recent
When you don't know the session ID, use `continue: true` (TypeScript) / `continue_conversation=True` (Python) to pick up the most recently modified session:
```typescript TypeScript
const q = query({
prompt: 'Continue',
options: {
auth: accessTokenFromEnv(),
continue: true,
},
});
```
```python Python
options = QoderAgentOptions(
auth=qodercli_auth(),
continue_conversation=True,
)
async with QoderSDKClient(options=options) as client:
await client.query("Continue")
async for msg in client.receive_response():
...
```
Do not pass `resume` together with `continue` (`continue_conversation` in Python).
## Forking Sessions
Derive a new session from an existing one, preserving the original context but obtaining a new session ID. The original session is unaffected:
```typescript TypeScript
const q = query({
prompt: 'Based on the prior context, explore a different direction',
options: {
auth: accessTokenFromEnv(),
resume: 'source-session-id',
forkSession: true,
},
});
```
```python Python
options = QoderAgentOptions(
auth=qodercli_auth(),
resume="source-session-id",
fork_session=True,
)
async with QoderSDKClient(options=options) as client:
await client.query("Based on the prior context, explore a different direction")
async for msg in client.receive_response():
...
```
To specify an ID for the forked new session:
```typescript TypeScript
options: {
auth: accessTokenFromEnv(),
resume: 'source-session-id',
forkSession: true,
sessionId: 'my-new-session-id',
}
```
```python Python
options = QoderAgentOptions(
auth=qodercli_auth(),
resume="source-session-id",
fork_session=True,
session_id="my-new-session-id",
)
```
## Field Reference
| Field (TypeScript / Python) | Type | Behavior |
| ------------------------------------ | ------------------ | ------------------------------------------------------------------------------------------- |
| `sessionId` / `session_id` | `string` / `str` | Alone: create a new session with this ID; with the fork field: the ID of the forked session |
| `resume` / `resume` | `string` / `str` | The session ID to resume |
| `continue` / `continue_conversation` | `boolean` / `bool` | `true` resumes the most recent session |
| `forkSession` / `fork_session` | `boolean` / `bool` | Used with `resume` to fork instead of continuing |
## Getting the Current Session ID
Listen for the `init` system message; in Python, `ResultMessage` also carries `session_id`—either works for bookkeeping:
```typescript TypeScript
for await (const msg of q) {
if (msg.type === 'system' && msg.subtype === 'init') {
console.log('session_id:', msg.session_id);
}
}
```
```python Python
from qoder_agent_sdk import ResultMessage, SystemMessage
current_session_id = None
async with QoderSDKClient(options=options) as client:
await client.query("Hello")
async for msg in client.receive_response():
if isinstance(msg, SystemMessage) and msg.subtype == "init":
current_session_id = msg.data["session_id"]
print(f"session: {current_session_id}")
elif isinstance(msg, ResultMessage):
current_session_id = msg.session_id
```
## User data directory
The user data directory stores session history, resources, logs, and other user-level CLI data. Set `QODER_CONFIG_DIR` through `options.env` to select this directory:
```typescript TypeScript
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Analyze this repository',
options: {
auth: accessTokenFromEnv(),
env: {
...process.env,
QODER_CONFIG_DIR: '/var/lib/my-agent/qoder',
},
},
});
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, access_token_from_env
options = QoderAgentOptions(
auth=access_token_from_env(),
env={"QODER_CONFIG_DIR": "/var/lib/my-agent/qoder"},
)
```
# External Session Storage
By default, qodercli keeps session history on the machine where it runs. In a multi-instance, container, or serverless deployment, the next request may reach a different machine that cannot read the earlier session.
External session storage keeps a **mirror** of each session in storage that your application controls. The mirror is an additional copy: qodercli still writes the session locally, and any host can continue a session later by using its session ID.
Use external storage when:
- requests can move between service instances
- local disks are temporary or unreliable
- your application must control access, encryption, backups, or retention
For an application that always runs on one machine, local session storage is usually enough.
## How it works
```text
first request
query()
-> qodercli writes the session locally
-> the SDK mirrors new session entries to your store
later request, on any host
query (with resume=session_id)
-> the SDK loads session history from your store
-> qodercli continues the session
```
Two properties follow from this design:
- **Writes are best-effort.** The SDK mirrors entries in the background. A failed write is reported but never stops the running conversation; see [Operations](#operations).
- **Entries are opaque.** Your store persists and returns SDK-defined transcript entries as-is. Your application does not need to understand qodercli's local file format.
## Quick start
`InMemorySessionStore` keeps data in the current process only. Use it to validate the wiring — that queries save to and resume from a store — before you connect a shared backend. It cannot demonstrate cross-host resume, because the data is gone when the process exits; for that, implement a real store. See [Implementing a store](#implementing-a-store).
```typescript TypeScript
import {
InMemorySessionStore,
qodercliAuth,
query,
} from '@qoder-ai/qoder-agent-sdk';
const store = new InMemorySessionStore();
const options = {
auth: qodercliAuth(),
cwd: '/path/to/project',
sessionStore: store,
};
// First query: run and capture the session ID.
let sessionId: string | undefined;
for await (const message of query({
prompt: 'Remember the number 42.',
options,
})) {
if (message.type === 'result') sessionId = message.session_id;
}
if (!sessionId) throw new Error('The first query did not return a session ID.');
// Later query: resume from the store and the model recalls prior context.
for await (const message of query({
prompt: 'What number did I ask you to remember?',
options: { ...options, resume: sessionId },
})) {
if (message.type === 'result') console.log(message.result); // -> "42"
}
```
```python Python
from qoder_agent_sdk import (
InMemorySessionStore,
QoderAgentOptions,
ResultMessage,
qodercli_auth,
query,
)
store = InMemorySessionStore()
base = dict(
auth=qodercli_auth(),
cwd="/path/to/project",
session_store=store,
)
# First query: run and capture the session ID.
session_id = None
async for message in query(
prompt="Remember the number 42.",
options=QoderAgentOptions(**base),
):
if isinstance(message, ResultMessage):
session_id = message.session_id
if session_id is None:
raise RuntimeError("The first query did not return a session ID.")
# Later query: resume from the store and the model recalls prior context.
async for message in query(
prompt="What number did I ask you to remember?",
options=QoderAgentOptions(**base, resume=session_id),
):
if isinstance(message, ResultMessage):
print(message.result) # -> "42"
```
Every host must use the same `cwd`, so the SDK identifies requests as belonging to the same project.
## Using a store in your application
For every query that should mirror or restore a session, pass the store in options (`sessionStore` in TypeScript, `session_store` in Python), then choose how to identify the session:
- **Known session ID** — pass `resume`.
- **The project's most recent session** — pass `continue: true` (TypeScript) / `continue_conversation=True` (Python). This requires the store to implement the session-listing method.
### Managing stored sessions
Session management functions operate on the store instead of local files. In TypeScript, pass the store via the `sessionStore` option; in Python, each function takes the store as its first argument:
```typescript TypeScript
import {
listSessions,
getSessionInfo,
getSessionMessages,
listSubagents,
getSubagentMessages,
renameSession,
tagSession,
forkSession,
deleteSession,
} from '@qoder-ai/qoder-agent-sdk';
const project = { dir: '/path/to/project', sessionStore: store };
const sessions = await listSessions(project);
const messages = await getSessionMessages(sessionId, project);
await renameSession(sessionId, 'Investigation #1', project);
await deleteSession(sessionId, project);
```
```python Python
from qoder_agent_sdk import (
list_sessions_from_store,
get_session_info_from_store,
get_session_messages_from_store,
list_subagents_from_store,
get_subagent_messages_from_store,
rename_session_via_store,
tag_session_via_store,
fork_session_via_store,
delete_session_via_store,
)
directory = "/path/to/project"
sessions = await list_sessions_from_store(store, directory=directory)
messages = await get_session_messages_from_store(
store, session_id, directory=directory
)
await rename_session_via_store(
store, session_id, "Investigation #1", directory=directory
)
await delete_session_via_store(store, session_id, directory=directory)
```
Listing sessions requires the store to implement the session-listing method; listing subagents requires `listSubkeys` / `list_subkeys`; deleting sessions requires `delete`. If `listSubkeys` / `list_subkeys` is implemented, the subagent-message getters use it too.
To copy an existing local session into the store—for example when migrating a machine that previously ran without external storage—use the import function; note the session ID comes first and the store second:
```typescript TypeScript
import { importSessionToStore } from '@qoder-ai/qoder-agent-sdk';
await importSessionToStore(sessionId, store, { dir: '/path/to/project' });
```
```python Python
from qoder_agent_sdk import import_session_to_store
await import_session_to_store(
session_id, store, directory="/path/to/project"
)
```
## Implementing a store
The SDK ships no production-ready storage implementation; applications implement the `SessionStore` interface (TypeScript) / protocol (Python) against the shared storage of their choice. Runnable reference implementations for Redis and PostgreSQL show the mechanics: see the [TypeScript examples](https://github.com/QoderAI/qoder-agent-sdk-samples/tree/main/typescript/external-session-storage) or [Python examples](https://github.com/QoderAI/qoder-agent-sdk-samples/tree/main/python/external-session-storage). They are starting points, not production-ready implementations.
```typescript TypeScript
type SessionKey = {
projectKey: string; // derived from cwd; identifies the project
sessionId: string; // the session UUID
subpath?: string; // set for subagent transcripts, e.g. "subagents/agent-"
};
type SessionStoreEntry = {
type: string;
uuid?: string;
timestamp?: string;
[key: string]: unknown; // opaque transcript line — store and return unchanged
};
interface SessionStore {
// Required
append(key: SessionKey, entries: SessionStoreEntry[]): Promise;
load(key: SessionKey): Promise;
// Optional — implement only the features you need
listSessions?(
projectKey: string,
): Promise>;
delete?(key: SessionKey): Promise;
listSubkeys?(key: Omit): Promise;
}
```
```python Python
from typing import NotRequired, Protocol, TypedDict
class SessionKey(TypedDict):
project_key: str # derived from cwd; identifies the project
session_id: str # the session UUID
subpath: NotRequired[str] # subagent transcripts, e.g. "subagents/agent-"
class SessionStoreEntry(TypedDict):
type: str
uuid: NotRequired[str]
timestamp: NotRequired[str]
# ...plus opaque SDK fields — store and return unchanged
class SessionStoreListEntry(TypedDict):
session_id: str
mtime: int | float # Unix epoch milliseconds
class SessionStore(Protocol):
# Required
async def append(
self, key: SessionKey, entries: list[SessionStoreEntry]
) -> None: ...
async def load(
self, key: SessionKey
) -> list[SessionStoreEntry] | None: ...
# Optional — implement only the features you need
async def list_sessions(
self, project_key: str
) -> list[SessionStoreListEntry]: ...
async def delete(self, key: SessionKey) -> None: ...
async def list_subkeys(
self, key: SessionKey # project_key + session_id, without subpath
) -> list[str]: ...
```
A `SessionKey` identifies one transcript. The main session has no `subpath`; each subagent transcript reuses the same project key and session ID with a different `subpath`. Treat keys and entries as opaque—store and return them verbatim, and do not parse message contents.
The two required methods provide save and resume. Each optional method unlocks a feature:
| Method | Feature enabled |
| -------------------------------- | ---------------------------------------------------- |
| `append`, `load` | Mirror a session and resume it by ID — required |
| `listSessions` / `list_sessions` | Resume the most recent session; list stored sessions |
| `delete` | Delete a session from the store |
| `listSubkeys` / `list_subkeys` | Fully restore and inspect subagent transcripts |
### Implementation checklist
- **Preserve append order per key**, and return the complete history from `load`. Replay depends on order.
- **Isolate keys.** Never return one key's entries under another.
- **Make `append` idempotent.** The SDK may retry a failed write with the same entries, so a retry must not duplicate history.
- **When listing sessions, `mtime` returns Unix-millisecond timestamps**, and only main sessions—those without a `subpath`—are returned.
- **Cascade deletes.** Deleting a main session must also delete its subagent transcripts.
- **`listSubkeys` / `list_subkeys` returns relative identifiers only**—never absolute paths, and never paths containing `.` or `..`. These become storage keys, and traversal segments would let transcripts escape their namespace.
- **Serialize concurrent writers** for the same session in the storage layer if more than one process can write it.
Use the SDK-provided conformance tests to check these generic behaviors (TypeScript ships `SessionStore` conformance tests in the SDK repo; Python provides `run_session_store_conformance` in `qoder_agent_sdk.testing`), and add concurrency and retry tests for your specific backend. Connection management, permissions, encryption, backups, migration, and retention remain the application's responsibility.
## Operations
**Failure handling.** External write failures never interrupt the ongoing conversation. After the final retry fails, the SDK emits a mirror-error message (`system/mirror_error` in TypeScript, `SDKMirrorErrorMessage` in Python). Monitor it if mirror integrity matters—the conversation may still complete even when a write fails.
**Tuning.**
- External reads wait up to 60 seconds by default. Tune with `loadTimeoutMs` / `load_timeout_ms`.
- The flush strategy (`sessionStoreFlush` / `session_store_flush`) defaults to `batched`. Setting `eager` mirrors entries sooner at the cost of more storage requests.
**Constraints.**
- If an explicitly resumed session is missing from the store, the SDK can still fall back to a local session with the same ID.
- The store cannot be combined with file checkpointing, custom transports, or the experimental Cloud Agent runtime (in TypeScript it also cannot be combined with `persistSession: false`). In TypeScript the store is supported on the built-in Process and Worker transports; Python requires the built-in subprocess transport.
- A store holds session history only. It does not hold authentication state, application configuration, file checkpoints, or retention policy.
# File Checkpoint and Rewind
File checkpointing records the state of local files modified by tools within a session. With `enableFileCheckpointing` (TypeScript) / `enable_file_checkpointing` (Python) enabled, callers can use `rewindFiles(userMessageId, ...)` / `rewind_files(user_message_id, ...)` to roll files back to the state when a given user message started processing.
The two capabilities work together: without checkpointing enabled, rewind has no file snapshots to use.
## Enabling File Checkpoint
```typescript TypeScript
import { query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Refactor src/foo.ts into a cleaner implementation',
options: {
cwd: '/path/to/project',
enableFileCheckpointing: true,
allowedTools: ['Read', 'Edit', 'Write'],
permissionMode: 'acceptEdits',
},
});
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, QoderSDKClient
options = QoderAgentOptions(
cwd="/path/to/project",
enable_file_checkpointing=True,
extra_args={"replay-user-messages": None},
allowed_tools=["Read", "Edit", "Write"],
permission_mode="acceptEdits",
)
async with QoderSDKClient(options=options) as client:
await client.query("Refactor src/foo.py into a cleaner implementation.")
async for message in client.receive_response():
...
```
In Python, keep the same active session with `QoderSDKClient` when you need to rewind later. The `extra_args={"replay-user-messages": None}` in the example is not the checkpoint switch; it makes the response stream replay `UserMessage`s carrying the `uuid` usable as rewind anchors—if your app lets users pick "go back to before this turn", you usually want it as well.
---
## Getting the rewind anchor: user message ID
Rewind is anchored on user message IDs, and the two SDKs obtain them differently:
- **TypeScript**: for precise rewinds, use structured input and generate the `uuid` yourself so the UI can reliably map back to "before that message".
- **Python**: the common approach is to capture the ID from `UserMessage.uuid` in the response stream (together with `extra_args={"replay-user-messages": None}`).
```typescript TypeScript
import { randomUUID } from 'node:crypto';
import { query } from '@qoder-ai/qoder-agent-sdk';
const userMessageId = randomUUID();
async function* input() {
yield {
type: 'user' as const,
uuid: userMessageId,
parent_tool_use_id: null,
message: {
role: 'user' as const,
content: [
{
type: 'text' as const,
text: 'Rewrite notes.txt as a two-line summary.',
},
],
},
};
// If your application needs to call rewind later within the same session,
// keep yielding subsequent user inputs here instead of closing the stream.
}
const q = query({
prompt: input(),
options: {
cwd: '/path/to/project',
enableFileCheckpointing: true,
allowedTools: ['Read', 'Write'],
permissionMode: 'acceptEdits',
},
});
```
```python Python
from qoder_agent_sdk import (
QoderAgentOptions,
QoderSDKClient,
ResultMessage,
UserMessage,
)
options = QoderAgentOptions(
cwd="/path/to/project",
enable_file_checkpointing=True,
extra_args={"replay-user-messages": None},
allowed_tools=["Write"],
permission_mode="acceptEdits",
)
checkpoint_id: str | None = None
async with QoderSDKClient(options=options) as client:
await client.query("Rewrite notes.txt as a two-line summary.")
async for message in client.receive_response():
if (
isinstance(message, UserMessage)
and message.uuid
and message.parent_tool_use_id is None
):
checkpoint_id = message.uuid
if isinstance(message, ResultMessage) and message.is_error:
raise RuntimeError(message.result or "Query failed.")
if checkpoint_id is None:
raise RuntimeError("No user message UUID was returned.")
```
The rewind anchor is the user message's `uuid`—not the `session_id`, and not the result message's ID. It is only valid within the session context that produced the checkpoint; other sessions cannot rewind with it directly.
---
## Dry Run Preview
Before executing a rewind, dry run first to preview the impact: whether rewinding is possible, which files are affected, and the overall insertion/deletion stats. A dry run modifies no files—ideal for confirmation dialogs or audit logs.
The returned `RewindFilesResult` contains these fields:
| Field | Type | Description |
| -------------- | ----------- | --------------------------------------------------------------------------------------------------------- |
| `canRewind` | `boolean` | Whether rollback can be performed. In dry run mode failures don't throw — this field indicates the status |
| `error` | `string?` | Diagnostic text when `canRewind` is false; can be shown to users directly |
| `filesChanged` | `string[]?` | Absolute paths of affected files — useful for listing each file that will be reverted in the UI |
| `insertions` | `number?` | Total number of added lines the rewind would undo (aggregate) |
| `deletions` | `number?` | Total number of deleted lines the rewind would undo (aggregate) |
> The SDK currently only returns the list of affected files and aggregate line-level statistics in `RewindFilesResult` — it does not return per-file diffs. If you need per-file differences, you can read the disk contents based on `filesChanged` after the dry run and compare them with the checkpoint, or use git/workspace diffing tools after executing the rewind.
```typescript TypeScript
const preview = await q.rewindFiles(userMessageId, { dryRun: true });
if (!preview.canRewind) {
// Show the diagnostic message in the UI.
console.error(preview.error);
return;
}
// Overall stats across all affected files.
console.log({
files: preview.filesChanged?.length ?? 0,
insertions: preview.insertions ?? 0,
deletions: preview.deletions ?? 0,
});
// Per-file listing — useful for a confirmation dialog.
for (const file of preview.filesChanged ?? []) {
console.log(`will be reverted: ${file}`);
}
```
```python Python
preview = await client.rewind_files(checkpoint_id, dry_run=True)
if not preview["canRewind"]:
print(preview.get("error", "Unable to rewind files."))
else:
print(
{
"files": len(preview.get("filesChanged", [])),
"insertions": preview.get("insertions", 0),
"deletions": preview.get("deletions", 0),
}
)
for file_path in preview.get("filesChanged", []):
print(f"will be reverted: {file_path}")
```
---
## Executing Rewind
After confirming the impact, execute the rewind by omitting the dry-run parameter:
```typescript TypeScript
const result = await q.rewindFiles(userMessageId);
console.log(result.filesChanged);
```
```python Python
result = await client.rewind_files(checkpoint_id)
if result["canRewind"]:
print(result.get("filesChanged", []))
```
Rewind only restores the local file state tracked by the checkpoint; it does not roll back conversation history. That is, the model still retains context from earlier turns; the UI must refresh the editor, file tree, or diff view itself based on `filesChanged`.
---
## Failure Semantics
| Call Form | Behavior When Rewind Is Not Possible |
| ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| Dry-run mode (`rewindFiles(id, { dryRun: true })` / `rewind_files(id, dry_run=True)`) | Returns `{ canRewind: false, error }`, convenient for showing diagnostics in the UI |
| Execute mode (`rewindFiles(id)` / `rewind_files(id)`) | The Promise rejects in TypeScript; Python raises. Callers should catch and surface the failure |
```typescript TypeScript
try {
await q.rewindFiles(userMessageId);
} catch (error) {
console.error(error instanceof Error ? error.message : String(error));
}
```
```python Python
try:
await client.rewind_files(checkpoint_id)
except Exception as exc:
print(str(exc))
```
Common failure causes: file checkpointing not enabled, the ID is not a valid user-message UUID, the ID belongs to another session, or the target message has no rewindable file snapshot.
---
## Settings Relationship
The `settings` field in options can be combined with the file-checkpoint switch. It accepts a `Settings` object or an absolute path string to a settings file:
- With a `settings` object, the SDK automatically merges in `general.fileCheckpointing.enabled = true`—no need to write it by hand. Existing settings fields are preserved; an existing `fileCheckpointing` config has its `enabled` overridden by the SDK option.
- With a settings file path string, the SDK does not rewrite the file; configure it yourself:
```json
{
"general": {
"fileCheckpointing": {
"enabled": true
}
}
}
```
Setting only the checkpoint switch without `settings` is enough for pure rewind scenarios.
```typescript TypeScript
options: {
cwd: '/path/to/project',
settings: { theme: 'dark' },
enableFileCheckpointing: true,
}
```
```python Python
options = QoderAgentOptions(
cwd="/path/to/project",
settings={"theme": "dark"},
enable_file_checkpointing=True,
)
```
---
## Boundaries
- Only local file checkpoints are rewound; external side effects from MCP tools, remote services, or databases are not undone.
- File changes made by writing files directly through `Bash` are not treated as rewindable file snapshots.
- File contents can be restored; directory-level side effects such as directory creation may not be undone.
- The checkpoint ID is bound to the session. After resuming the same session, the corresponding ID can still be used; it cannot be mixed across different sessions.
---
## Field Reference
| Entry (TypeScript / Python) | Description |
| -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `enableFileCheckpointing` / `enable_file_checkpointing` | Enables file checkpointing for rewind |
| `settings` / `settings` | Settings passed to the CLI; with an object the SDK merges `general.fileCheckpointing.enabled` |
| `extra_args` (Python only) | Pass `{"replay-user-messages": None}` to receive `UserMessage.uuid` in the stream |
| `q.rewindFiles(userMessageId, { dryRun })` / `client.rewind_files(user_message_id, dry_run=False)` | Preview or execute a file rewind |
---
## Return Value Reference
```typescript
type RewindFilesResult = {
canRewind: boolean;
error?: string;
filesChanged?: string[];
insertions?: number;
deletions?: number;
};
```
---
## Best Practices
- **Save the user message ID**: apps that need rewind should save the `uuid` when sending messages (in Python, bind `UserMessage.uuid` to your UI message records) instead of reverse-searching UI text.
- **Dry run before rewinding**: Show the impact scope first, then let the user confirm the rollback.
- **Refresh UI after rollback**: Rewind only changes files, not conversation history; the UI needs to reload relevant views based on `filesChanged`.
- **Show `error` to users on failure**: the `error` text when `canRewind` is false is usually suitable for end-user diagnostics as-is.
# Tools
Tools are capabilities the model can call while executing a task. The Qoder Agent SDK supports two kinds of tools:
- **Built-in tools**: Provided by Qoder CLI, such as reading files, searching, executing commands, and invoking subagents.
- **Custom tools**: defined by SDK users and exposed to the model as in-process MCP servers—TypeScript uses `tool()` + `createSdkMcpServer()`, Python uses the `@tool()` decorator + `create_sdk_mcp_server()`.
This page focuses on custom tools. For more MCP server integration options see [MCP integration](/cli/sdk/mcp); for the full permission system see [Permissions](/cli/sdk/permissions); for the full built-in tool list see [SDK References](/cli/sdk/references).
## Built-in Tools
With built-in tools you don't implement anything yourself—options control which tools this session can see, which are pre-approved, and which are denied.
```typescript TypeScript
query({
prompt: 'Read this repository and summarize risks in the authentication module. Do not modify files.',
options: {
auth: accessTokenFromEnv(),
cwd: '/path/to/project',
tools: ['Read', 'Grep', 'Glob'],
allowedTools: ['Read', 'Grep', 'Glob'],
},
});
```
```python Python
import asyncio
from qoder_agent_sdk import QoderAgentOptions, qodercli_auth, query
async def main():
options = QoderAgentOptions(
auth=qodercli_auth(),
cwd="/path/to/project",
tools=["Read", "Grep", "Glob"],
allowed_tools=["Read", "Grep", "Glob"],
)
async for message in query(
prompt=(
"Read this repository and summarize risks in the authentication "
"module. Do not modify files."
),
options=options,
):
print(message)
asyncio.run(main())
```
Common built-in tools include `Read`, `Edit`, `Write`, `Bash`, `Glob`, `Grep`, `WebFetch`, `WebSearch`, `Agent`, and more. Tool names are determined by the underlying Qoder CLI; permission configuration should use the tool names the CLI exposes to the model. See [SDK References](/cli/sdk/references) for the full list, names, and input/output structures.
---
## Custom Tools
Define a custom tool when you want the model to call your own business capability, such as order lookup, internal knowledge base search, approval system calls, or read-only database access.
Custom tools usually involve three steps:
1. Create the tool: TypeScript uses `tool()`; Python decorates an `async def` handler with `@tool()`.
2. Register it on an in-process MCP server: `createSdkMcpServer()` / `create_sdk_mcp_server()`.
3. Wire it up via the MCP servers config in options, and control invocation with permission settings.
---
## Custom Tool Integration Steps
First, here is a complete minimal example. The following sections then explain each step.
```typescript TypeScript
import {
accessTokenFromEnv,
createSdkMcpServer,
query,
tool,
} from '@qoder-ai/qoder-agent-sdk';
import { z } from 'zod';
const lookupOrder = tool(
'lookup_order',
'Look up an order by order ID.',
{
orderId: z.string().describe('Order ID, such as O-1001'),
},
async ({ orderId }) => {
const order = await orders.find(orderId);
if (!order) {
return {
isError: true,
content: [{ type: 'text', text: `Order not found: ${orderId}` }],
};
}
return {
content: [{ type: 'text', text: JSON.stringify(order) }],
};
},
{ annotations: { readOnlyHint: true } },
);
const orderTools = createSdkMcpServer({
name: 'orders',
tools: [lookupOrder],
});
const messages = query({
prompt: 'Check the status of order O-1001 and summarize it in one sentence.',
options: {
auth: accessTokenFromEnv(),
mcpServers: { orders: orderTools },
allowedTools: ['mcp__orders__lookup_order'],
},
});
for await (const message of messages) {
if (message.type === 'result') {
console.log(message.result);
}
}
```
```python Python
import asyncio
import json
from mcp.types import ToolAnnotations
from qoder_agent_sdk import (
QoderAgentOptions,
create_sdk_mcp_server,
qodercli_auth,
query,
tool,
)
orders = {
"O-1001": {"order_id": "O-1001", "status": "shipped", "eta": "2026-05-20"},
}
@tool(
"lookup_order",
"Look up an order by order ID and return its status as JSON.",
{"order_id": str},
annotations=ToolAnnotations(readOnlyHint=True),
)
async def lookup_order(args):
order_id = args["order_id"]
order = orders.get(order_id)
if order is None:
return {
"is_error": True,
"content": [{"type": "text", "text": f"Order not found: {order_id}"}],
}
return {"content": [{"type": "text", "text": json.dumps(order)}]}
order_tools = create_sdk_mcp_server(
name="orders",
tools=[lookup_order],
)
async def main():
options = QoderAgentOptions(
auth=qodercli_auth(),
mcp_servers={"orders": order_tools},
allowed_tools=["mcp__orders__lookup_order"],
)
async for message in query(
prompt="Check the status of order O-1001 and summarize it in one sentence.",
options=options,
):
print(message)
asyncio.run(main())
```
### Step 1: Create the tool
This step defines the tool itself: its name, description, input parameters, execution logic, and metadata.
#### Parameters
TypeScript's `tool()` takes 5 parameters; Python's `@tool()` decorator takes 4:
| Parameter | Required | Meaning |
| ---------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `name` | Yes | Unique identifier of the tool within its MCP server |
| `description` | Yes | Model-facing description: when to use the tool, what it does, what it returns |
| `inputSchema` / `input_schema` | Yes | Tool input parameters: TypeScript takes a Zod raw shape; Python supports a simple dict, `TypedDict`, or a full JSON Schema dict |
| `handler` (TypeScript) | Yes | Async function that receives parsed arguments and returns a `CallToolResult`; in Python the decorated `async def` is the handler |
| `extras.annotations` (TypeScript) / `annotations` (Python) | No | MCP tool annotations such as `readOnlyHint`, `destructiveHint`, `openWorldHint` |
Python tool handlers must be async functions, usually taking one `args` dict. If the handler declares a second positional parameter, the SDK passes a `ToolInvocationContext` whose `signal` is an `asyncio.Event` set when the CLI cancels the in-flight tool call—useful for long tasks to stop proactively:
```typescript TypeScript
tool(
'search_docs',
'Search internal product documentation.',
{ query: z.string().describe('Search keywords') },
async ({ query }) => ({ content: [{ type: 'text', text: query }] }),
);
```
```python Python
@tool("search_docs", "Search internal product documentation.", {"query": str})
async def search_docs(args):
return {"content": [{"type": "text", "text": f"Searching: {args['query']}"}]}
@tool("watch", "Watch a counter until max.", {"max": int})
async def watch(args, extra):
for i in range(args["max"]):
if extra.signal.is_set():
return {"content": [{"type": "text", "text": f"aborted at {i}"}]}
await asyncio.sleep(0.01)
return {"content": [{"type": "text", "text": "done"}]}
```
#### Configure Input Parameters
The two SDKs declare input schemas differently; both are normalized to MCP-protocol JSON Schema.
**TypeScript**: pass a Zod raw shape—a field object, not `z.object(...)`:
```typescript
{
query: z.string().describe('Search keywords'),
maxResults: z.number().int().min(1).max(10).optional()
.describe('Maximum number of snippets to return'),
source: z.enum(['docs', 'tickets', 'wiki']).default('docs')
.describe('Where to search'),
}
```
| Need | TypeScript syntax |
| ------------------ | --------------------------------------- |
| Required string | `z.string().describe('...')` |
| Optional parameter | `z.string().optional().describe('...')` |
| Default value | `z.number().default(5)` |
| Enum | `z.enum(['docs', 'tickets'])` |
| Numeric range | `z.number().min(1).max(10)` |
**Python**: three styles are supported.
Style 1: a simple dict, for a handful of simple parameters. Keys are parameter names, values are Python types; every key is required in this style. Use `typing.Annotated` to attach descriptions:
```python
from typing import Annotated
input_schema = {
"query": Annotated[str, "Search keywords"],
"max_results": Annotated[int, "Maximum number of snippets to return"],
}
```
| Python form | JSON Schema meaning |
| --------------------- | ---------------------------------- |
| `str` | `{"type": "string"}` |
| `int` | `{"type": "integer"}` |
| `float` | `{"type": "number"}` |
| `bool` | `{"type": "boolean"}` |
| `list[str]` | String array |
| `dict` | Object |
| `Annotated[T, "..."]` | Adds `description` to `T`'s schema |
Style 2: `TypedDict`, for many fields, optional fields, or reusable type definitions. Mark optional fields with `NotRequired` (importable from `typing` on Python 3.11+; use `typing_extensions` on 3.10):
```python
from typing import Annotated, TypedDict
from typing_extensions import NotRequired
class SearchInput(TypedDict):
query: Annotated[str, "Search keywords"]
max_results: NotRequired[Annotated[int, "Maximum snippets to return"]]
@tool("search_docs", "Search internal product documentation.", SearchInput)
async def search_docs(args):
limit = args.get("max_results", 5)
return {"content": [{"type": "text", "text": f"{args['query']} ({limit})"}]}
```
Style 3: a full JSON Schema dict, for enums, numeric ranges, string format constraints, or nested objects:
```python
input_schema = {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search keywords"},
"source": {
"type": "string",
"enum": ["docs", "tickets", "wiki"],
"description": "Where to search",
},
"max_results": {"type": "integer", "minimum": 1, "maximum": 10},
},
"required": ["query"],
}
```
#### Configure Tool Metadata
annotations carry MCP tool annotations. The SDK puts them on the MCP tool definition, and the CLI can use them for scheduling, permissions, or status display.
```typescript TypeScript
tool(
'search_docs',
'Search internal product documentation.',
{ query: z.string().describe('Search keywords') },
async ({ query }) => ({ content: [{ type: 'text', text: query }] }),
{
annotations: {
readOnlyHint: true,
destructiveHint: false,
openWorldHint: false,
},
},
);
```
```python Python
from mcp.types import ToolAnnotations
@tool(
"search_docs",
"Search internal product documentation.",
{"query": str},
annotations=ToolAnnotations(
title="Search docs",
readOnlyHint=True,
destructiveHint=False,
openWorldHint=False,
),
)
async def search_docs(args):
return {"content": [{"type": "text", "text": args["query"]}]}
```
Common fields:
| Field | Type | Meaning |
| ----------------------------- | --------- | --------------------------------------------------------------------------------------------------- |
| `title` | `string` | Human-readable tool title |
| `readOnlyHint` | `boolean` | Marks the tool as read-only, changing no state |
| `destructiveHint` | `boolean` | Marks the tool as potentially modifying or deleting data |
| `openWorldHint` | `boolean` | Marks the tool as reaching external systems or the network |
| `maxResultSizeChars` (Python) | `int` | Passed to the CLI via `_meta["anthropic/maxResultSizeChars"]` to relax the tool output length limit |
Note: these fields do not replace permission configuration. Whether a tool may run is still decided by `tools`, allow/deny rules, the permission mode, the permission callback, and hooks. The annotations echoed in MCP status may also use the CLI-projected names `readOnly`, `destructive`, `openWorld` instead of the raw MCP `*Hint` names; keep a mapping on your side if the host UI needs them.
### Step 2: Register with an MCP Server
`createSdkMcpServer()` / `create_sdk_mcp_server()` registers one or more tools as a same-process MCP server. The server name becomes part of the full tool name, so keep it short and stable.
```typescript TypeScript
const kbTools = createSdkMcpServer({
name: 'kb',
version: '1.0.0',
tools: [searchDocs],
});
```
```python Python
kb_tools = create_sdk_mcp_server(
name="kb",
version="1.0.0",
tools=[search_docs],
)
```
| Field | How to set it | Description |
| --------- | --------------------------- | ------------------------------------------------------------- |
| `name` | For example `kb`, `orders` | Server name; forms full tool names like `mcp__{name}__{tool}` |
| `version` | For example `'1.0.0'` | Informational version, optional |
| `tools` | `[searchDocs, lookupOrder]` | Tools registered to this server |
Python's `create_sdk_mcp_server()` validates synchronously: server name / tool names / tool descriptions must be non-empty strings, and tool names must be unique within a server.
### Step 3: Attach to `query()`
Once the server is in the MCP servers config, the CLI discovers its tools and calls back into your handler through the SDK when the model needs them.
```typescript TypeScript
query({
prompt: 'Search docs for the refund policy and summarize it.',
options: {
auth: accessTokenFromEnv(),
mcpServers: { kb: kbTools },
allowedTools: ['mcp__kb__search_docs'],
},
});
```
```python Python
options = QoderAgentOptions(
auth=qodercli_auth(),
mcp_servers={"kb": kb_tools},
allowed_tools=["mcp__kb__search_docs"],
)
async for message in query(
prompt="Search docs for the refund policy and summarize it.",
options=options,
):
print(message)
```
The full custom tool name format is:
```text
mcp__{serverName}__{toolName}
```
For example, with server name `orders` and tool name `lookup_order`, the full tool name is `mcp__orders__lookup_order`. This full name is used in tool allowlists/denylists, permission callbacks, hooks matchers, and subagent `tools` configuration.
Python's `QoderSDKClient` multi-turn sessions use the same `mcp_servers` configuration:
```python Python
from qoder_agent_sdk import QoderSDKClient
options = QoderAgentOptions(
auth=qodercli_auth(),
mcp_servers={"kb": kb_tools},
allowed_tools=["mcp__kb__search_docs"],
)
async with QoderSDKClient(options=options) as client:
await client.query("Search docs for the refund policy.")
async for message in client.receive_response():
print(message)
```
---
## Controlling Tool Permissions
When the model calls tools, the SDK provides multiple permission layers. You can decide:
- Which tools are provided to the current session.
- Which tools are allowed by default.
- Which tools are explicitly denied.
- Whether your application should decide when a tool requires approval.
### Permission Control Overview
| Method (TypeScript / Python) | Effect | Granularity | When to use |
| ------------------------------------------------------------------------ | ------------------------------------------------- | ----------- | ---------------------------------------------------------- |
| `tools` | Limits the visible tool set for this session | Session | Narrow the tools the model can see at the source |
| `allowedTools` / `allowed_tools`, `disallowedTools` / `disallowed_tools` | Pre-approve or deny specific tools | Per tool | You know exactly which tools to allow or deny |
| `permissionMode` / `permission_mode` | Set the session's default permission policy | Global | Quickly switch plan mode, auto-accept edits, bypass, etc. |
| `canUseTool` / `can_use_tool` | Calls your code when a tool needs user approval | Per call | Decide from tool input, or handle `AskUserQuestion` |
| `hooks.PreToolUse` | Intercepts tool calls through the hooks lifecycle | Call | You already use hooks and want shared auditing or blocking |
These approaches compose. A common pattern: narrow the visible tool set with `tools`, set static rules with allow/deny, then use the permission callback for argument-level decisions.
### Approach 1: tool set plus allow/deny rules
`tools` controls the session's visible tool set; allow/deny rules control permissions. Custom MCP tools must use full tool names.
```typescript TypeScript
// Only expose read/search tools to this session.
query({
prompt: 'Analyze the repository without editing files.',
options: {
tools: ['Read', 'Glob', 'Grep'],
allowedTools: ['Read', 'Glob', 'Grep'],
},
});
// Explicitly deny high-risk tools.
query({
prompt: 'Review the project and report issues.',
options: {
disallowedTools: ['Bash', 'Write', 'Edit'],
},
});
// Use full names for custom MCP tools.
query({
prompt: 'Check order O-1001.',
options: {
mcpServers: { orders: orderTools },
allowedTools: ['mcp__orders__lookup_order'],
},
});
// Disable all tools. The model can only answer from its context.
query({
prompt: 'Explain what this SDK does at a high level.',
options: { tools: [] },
});
```
```python Python
# Only expose read/search tools to this session.
QoderAgentOptions(
tools=["Read", "Glob", "Grep"],
allowed_tools=["Read", "Glob", "Grep"],
)
# Explicitly deny high-risk tools.
QoderAgentOptions(
disallowed_tools=["Bash", "Write", "Edit"],
)
# Use full names for custom MCP tools.
QoderAgentOptions(
mcp_servers={"orders": order_tools},
allowed_tools=["mcp__orders__lookup_order"],
)
# Disable all tools. The model can only answer from its context.
QoderAgentOptions(tools=[])
```
When the same tool matches both allow and deny rules, the deny rule takes precedence.
### Approach 2: permission mode
The permission mode sets the whole session's default permission behavior with one line.
```typescript TypeScript
query({
prompt: 'Refactor the code.',
options: {
permissionMode: 'acceptEdits',
},
});
```
```python Python
QoderAgentOptions(
permission_mode="acceptEdits",
)
```
| Mode | Effect |
| ------------------- | -------------------------------------------------------------------------------------- |
| `default` | Standard permission behavior; sensitive operations follow rules or runtime policy |
| `acceptEdits` | Auto-accepts file edits; other sensitive operations still follow the permission policy |
| `bypassPermissions` | Skips permission checks; requires the explicit skip confirmation as well |
| `yolo` | Compatibility alias of `bypassPermissions`; also requires explicit confirmation |
| `plan` | Plan mode, for having the model produce a proposal first |
| `dontAsk` | No interactive prompts; operations not pre-approved or allowed by rules are denied |
| `auto` | The runtime decides allow or deny automatically |
### Approach 3: permission callback
For ordinary tools, the SDK calls `canUseTool` / `can_use_tool` only when user approval is required. Tools that were already allowed, denied, or handled automatically by the permission mode do not trigger it. `AskUserQuestion` is the exception: after the callback is configured, it still runs for a real user answer unless interaction is explicitly disabled. See [Approval and User Input](/cli/sdk/user-input) for the full rules and answer format.
```typescript TypeScript
query({
prompt: 'Check order O-1001.',
options: {
auth: accessTokenFromEnv(),
mcpServers: { orders: orderTools },
allowedTools: ['mcp__orders__lookup_order'],
async canUseTool(toolName, input, options) {
if (toolName !== 'mcp__orders__lookup_order') {
return {
behavior: 'deny',
message: 'Only order lookup is allowed in this workflow.',
toolUseID: options.toolUseID,
};
}
return {
behavior: 'allow',
updatedInput: input,
toolUseID: options.toolUseID,
};
},
},
});
```
```python Python
from typing import Any
from qoder_agent_sdk import (
PermissionResultAllow,
PermissionResultDeny,
ToolPermissionContext,
)
async def can_use_tool(
tool_name: str,
input_data: dict[str, Any],
context: ToolPermissionContext,
):
if tool_name != "mcp__orders__lookup_order":
return PermissionResultDeny(
message="Only order lookup is allowed in this workflow.",
)
return PermissionResultAllow(updated_input=input_data)
options = QoderAgentOptions(
auth=qodercli_auth(),
mcp_servers={"orders": order_tools},
allowed_tools=["mcp__orders__lookup_order"],
can_use_tool=can_use_tool,
)
```
Common return values:
| Return | Effect |
| ------------------------------------ | ---------------------------------------------------------- |
| allow | Executes with the original arguments |
| allow + updated input | Executes with replaced tool arguments |
| deny + `message` | Rejects; the model sees the reason and can try another way |
| deny + `message` + `interrupt: true` | Rejects and interrupts the current agent loop |
When using custom tools in a subagent, use the full tool name as well:
```typescript TypeScript
query({
prompt: 'Use the order-support agent to check order O-1001.',
options: {
auth: accessTokenFromEnv(),
mcpServers: { orders: orderTools },
allowedTools: ['Agent'],
agents: {
'order-support': {
description: 'Handles order lookup and explains order status.',
prompt: 'Use order tools to answer order status questions clearly.',
tools: ['mcp__orders__lookup_order'],
},
},
},
});
```
```python Python
from qoder_agent_sdk import AgentDefinition
options = QoderAgentOptions(
auth=qodercli_auth(),
mcp_servers={"orders": order_tools},
allowed_tools=["Agent"],
agents={
"order-support": AgentDefinition(
description="Handles order lookup and explains order status.",
prompt="Use order tools to answer order status questions clearly.",
tools=["mcp__orders__lookup_order"],
),
},
)
```
### Method 4: `hooks.PreToolUse`
If you already use the hooks system, use `PreToolUse` to intercept or audit tool calls in one place.
```typescript TypeScript
query({
prompt: 'Run the test command.',
options: {
allowedTools: ['Bash'],
hooks: {
PreToolUse: [
{
matcher: 'Bash',
hooks: [
async (input) => {
const command = (input.tool_input as { command: string }).command;
if (command.includes('rm -rf')) {
return {
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'deny',
permissionDecisionReason: 'rm -rf is not allowed',
},
};
}
return {
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'allow',
},
};
},
],
},
],
},
},
});
```
```python Python
from qoder_agent_sdk import HookMatcher
async def block_dangerous_bash(inp, tool_use_id, context):
command = inp.get("tool_input", {}).get("command", "")
if "rm -rf" in command:
return {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "rm -rf is not allowed",
}
}
return {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
}
}
options = QoderAgentOptions(
allowed_tools=["Bash"],
hooks={
"PreToolUse": [
HookMatcher(matcher="Bash", hooks=[block_dangerous_bash]),
],
},
)
```
`PreToolUse`'s `permissionDecision` can be `allow`, `deny`, `ask`, or `defer`. See [Permissions](/cli/sdk/permissions) for the full permission strategy.
---
## How the SDK Handles Tool Errors
Tool handlers have several error paths.
### Business failures: return an explicit error flag
For expected business failures, return the error flag (`isError: true` in TypeScript, `is_error: True` in Python). The SDK converts the result into an MCP `CallToolResult` for the CLI; the model sees the failure content and may retry or choose another approach.
```typescript TypeScript
return {
isError: true,
content: [{
type: 'text',
text: JSON.stringify({
error: 'VALIDATION_ERROR',
message: 'Only SELECT statements are allowed.',
}),
}],
};
```
```python Python
return {
"is_error": True,
"content": [
{
"type": "text",
"text": json.dumps(
{
"error": "VALIDATION_ERROR",
"message": "Only SELECT statements are allowed.",
}
),
}
],
}
```
Good cases for the error flag:
- Arguments are valid, but no business result exists, such as an order not found.
- A security policy rejects execution, such as only allowing `SELECT` queries.
- An external service returns a business error that can be explained.
### Unexpected Exception: Handler Throws
If the handler throws, the MCP layer converts the exception into an error result, and the agent loop won't crash from an ordinary tool exception. But the model usually only sees the exception message—less controlled in format and content than an explicit error flag.
```typescript TypeScript
const toolThatMayThrow = tool(
'fetch_user',
'Fetch a user by ID.',
{ userId: z.string() },
async ({ userId }) => {
const response = await userService.fetch(userId);
if (!response.ok) {
throw new Error('User service failed');
}
return { content: [{ type: 'text', text: await response.text() }] };
},
);
```
```python Python
@tool("fetch_user", "Fetch a user by ID.", {"user_id": str})
async def fetch_user(args):
response = await user_service.fetch(args["user_id"])
if not response.ok:
raise RuntimeError("User service failed")
return {"content": [{"type": "text", "text": await response.text()}]}
```
Recommendation: use the explicit error flag for expected business failures; throw only for truly unexpected exceptions.
### Malformed returns: wrapped as errors by the SDK (Python)
The Python SDK performs a runtime fallback check on handler return values:
- Returning `None`: converted to error text explaining that the handler must return a dict containing `"content"`.
- Returning a non-dict (e.g., string, number, list): converted to text content and marked `isError=True`.
- Returning a dict but without `"content"`: converted to error text and lists the actual keys.
- Returning unsupported content types: that content block is skipped and a warning is logged.
These fallbacks prevent the model from seeing empty successful results, but business code should still always return the standard structure.
---
## Tool Return Values
Tool handlers return an MCP `CallToolResult` (a dict in Python, converted by the SDK). Text content is the most common:
```typescript TypeScript
return {
content: [{ type: 'text', text: 'done' }],
};
```
```python Python
return {
"content": [{"type": "text", "text": "done"}],
}
```
You can also return structured JSON strings, which help the model understand and continue processing:
```typescript TypeScript
return {
content: [{
type: 'text',
text: JSON.stringify({
orderId: 'O-1001',
status: 'shipped',
eta: '2026-05-20',
}),
}],
};
```
```python Python
return {
"content": [
{
"type": "text",
"text": json.dumps(
{
"order_id": "O-1001",
"status": "shipped",
"eta": "2026-05-20",
}
),
}
],
}
```
Common content blocks:
| Type | Shape | Description |
| ----------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Text | `{ type: 'text', text }` | Most common; suitable for natural language or JSON strings |
| Image | `{ type: 'image', data, mimeType }` | `data` is base64 |
| Audio | `{ type: 'audio', data, mimeType }` | `data` is base64 (TypeScript) |
| Resource link | `{ type: 'resource_link', uri, name?, description?, mimeType? }` | Returns a referenceable resource; Python degrades it to text, concatenating `name` / `uri` / `description` for the model |
| Embedded resource | `{ type: 'resource', resource }` | Returns text or binary resource content; Python converts embedded text resources to `TextContent` |
The Python edition has two result differences worth noting:
- The handler-returned dict's top-level `_meta` is not propagated to `CallToolResult`.
- When the handler indicates an error, use the Python field name `"is_error": True`, not the MCP/TypeScript-style `isError`. The SDK maps it to the MCP result internally.
---
## Common Pitfalls
- When writing permission configuration for custom tools, use the full `mcp__server__tool` name.
- In TypeScript, `tool()`'s third parameter takes a Zod raw shape—do not pass `z.object(...)`.
- All fields in a Python simple-dict schema are required; use `TypedDict + NotRequired` or a full JSON Schema for optional fields.
- For enums, numeric ranges, nested objects, or string pattern/format constraints, use a full JSON Schema dict in Python.
- Python handlers must be `async def` and return a dict containing a `"content"` list.
- Tool descriptions should state "when to use it, what it does, what it returns"—never just `query` or `helper`.
- `readOnlyHint` is tool metadata and a scheduling hint, not a permission switch. Whether execution is allowed is still determined by permission configuration.
- Avoid putting a huge all-purpose business entry point into one universal tool. A tool should complete one clear class of action.
---
## Continue Reading
- [Tools Reference](/cli/sdk/references): built-in tool list, tool creation APIs, `CallToolResult`, built-in tool I/O types.
- [MCP Integration](/cli/sdk/mcp): in-process, stdio, SSE, HTTP, OAuth, and other MCP server integration methods.
- [Permissions](/cli/sdk/permissions): permission modes, tool allowlists, permission callbacks, permission rule updates.
- [Subagent Guide](/cli/sdk/agents): Let different agents use different tool sets.
# MCP Integration
MCP (Model Context Protocol) is the open protocol AI agents use to call external tools. With the SDK you define MCP servers and configure tools for agents; connection management, tool discovery, OAuth, and status sync are handled by the underlying CLI.
## Architecture Overview
```
┌────────────────────────────────────────────────────────────┐
│ Your application (SDK Host) │
│ │
│ ┌──────────────────────────┐ │
│ │ createSdkMcpServer(...) │ ← In-Process tools │
│ │ + tool(...) │ defined inline, no proc │
│ └──────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────┐ │
│ │ query({ mcpServers }) │── stdio ─▶ qodercli child │
│ └──────────────────────────┘ │
│ │ │
│ ├── stdio ──▶ MCP server (process)
│ ├── sse ──▶ MCP server (HTTP/SSE)
│ └── http ──▶ MCP server (Streamable HTTP)
└────────────────────────────────────────────────────────────┘
```
- **In-Process**: the tool is just an ordinary async function (JS / Python) running in your own process. The server instance talks to the CLI over the SDK control channel—no extra process is spawned.
- **External**: You declare a child process or remote URL in the configuration; the CLI handles connection, discovery, and invocation.
---
## Three Integration Methods
| Method | Config type | Process Boundary | Use Case |
| -------------- | ------------------------------------------------------------------- | ---------------- | ----------------------------------------------------------- |
| **In-Process** | `'sdk'` (created by `createSdkMcpServer` / `create_sdk_mcp_server`) | Same process | Custom business tools that need direct access to host state |
| **Stdio** | `'stdio'` (can be omitted) | Child process | Existing MCP toolkits (`@modelcontextprotocol/server-*`) |
| **SSE / HTTP** | `'sse'` / `'http'` | Remote | Remote services, SaaS tools, services requiring OAuth |
The three approaches can be **mixed**—register multiple servers of different types in the same session.
> 💡 In Python, `mcp_servers` also accepts a `str` / `pathlib.Path` pointing to a JSON config file; the SDK passes it through to the CLI as `--mcp-config `.
---
## In-Process Server (Recommended)
In-process tools are the most direct extension path: define an ordinary async function with a schema declaration and the agent can call it. For tool creation / schema / handler details see [Tools](/cli/sdk/tools); this section only covers MCP server assembly.
### 30-Second Getting Started
```typescript TypeScript
import { query, createSdkMcpServer, tool } from '@qoder-ai/qoder-agent-sdk';
import { z } from 'zod';
const greet = tool(
'greet',
'Greet someone.',
{ name: z.string().describe('Recipient name') },
async ({ name }) => ({
content: [{ type: 'text', text: `Hello, ${name}!` }],
}),
);
const server = createSdkMcpServer({
name: 'my_tools',
tools: [greet],
});
const q = query({
prompt: 'Use the greet tool to greet Alice',
options: {
mcpServers: { my_tools: server },
allowedTools: ['mcp__my_tools__greet'],
},
});
for await (const msg of q) {
if (msg.type === 'result') console.log(msg.result);
}
```
```python Python
import asyncio
from typing import Annotated
from qoder_agent_sdk import (
QoderAgentOptions,
create_sdk_mcp_server,
query,
tool,
)
@tool("greet", "Greet someone.", {"name": Annotated[str, "Recipient name"]})
async def greet(args):
return {"content": [{"type": "text", "text": f"Hello, {args['name']}!"}]}
server = create_sdk_mcp_server(name="my_tools", tools=[greet])
async def main():
options = QoderAgentOptions(
mcp_servers={"my_tools": server},
allowed_tools=["mcp__my_tools__greet"],
)
async for msg in query(prompt="Use the greet tool to greet Alice", options=options):
print(msg)
asyncio.run(main())
```
### Full signatures
```typescript TypeScript
function tool(
name: string,
description: string,
inputSchema: Schema,
handler: (args: z.infer>, extra: unknown) => Promise,
extras?: ToolExtras,
): SdkMcpToolDefinition;
type ToolExtras = {
annotations?: ToolAnnotations; // see "What annotations are actually consumed" below
};
function createSdkMcpServer(options: {
name: string; // server name (determines tool prefix mcp____)
version?: string; // defaults to '1.0.0'
tools?: Array>;
}): McpSdkServerConfigWithInstance;
```
```python Python
def tool(
name: str,
description: str,
input_schema: type | dict[str, Any],
annotations: ToolAnnotations | None = None,
) -> Callable[[Handler], SdkMcpTool[Any]]: ...
def create_sdk_mcp_server(
name: str,
version: str = "1.0.0",
tools: list[SdkMcpTool[Any]] | None = None,
) -> McpSdkServerConfig: ...
```
| Parameter | Description |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| `name` (tool) | Tool name; the fully-qualified name will be `mcp____` |
| `description` | Description for the model, determining when the AI invokes it — **clearly state what the tool does and when to use it** |
| `inputSchema` / `input_schema` | TypeScript takes a Zod raw shape (not `z.object(...)`); Python supports a simple dict / `TypedDict` / full JSON Schema dict |
| `handler` | Actual logic, returns `CallToolResult` |
| `annotations` | MCP tool annotations; see table below |
| `name` (server) | Server name (determines tool prefix `mcp____`) |
| `version` | Defaults to `'1.0.0'` |
| `tools` | List of tools |
The return value has the shape `{ type: 'sdk', name, instance }`—drop it straight into the MCP servers config.
> ⚠️ **Do not reuse the same server config across multiple `query()` calls**: Each query binds an independent transport. Reusing the same config has no side effects, but you won't get "cross-query shared state" capability either — for shared state, place it in module scope outside the handler closure.
#### Annotations Actually Consumed
The following three fields are actually consumed by the SDK and echoed back to the host via MCP status queries (TypeScript's `mcpServerStatus().tools[i].annotations`, Python's `get_mcp_status().mcpServers[i].tools[i].annotations`):
| Field | What it does | Host-side reads as |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------- |
| `readOnlyHint` | Declares the tool **read-only**. Read-only tools can run concurrently (no mutual blocking within a batch); the TUI tool details render a `[read-only]` badge | `annotations.readOnly` |
| `destructiveHint` | Declares the tool performs **destructive operations**. The TUI renders a `[destructive]` badge in tool details | `annotations.destructive` |
| `openWorldHint` | Declares the tool reaches the **outside world** (web search, third-party APIs). The TUI tool details render an `[open-world]` badge | `annotations.openWorld` |
> Note the host-side field names drop the `Hint` suffix: `readOnlyHint` → `annotations.readOnly`, and so on. The `annotations` object only contains explicitly set fields.
>
> ⚠️ **These three fields do not affect auto-mode permission decisions.** The CLI treats server-declared annotations as unverifiable hints (servers can freely under-/over-declare) and keeps them out of the permission pipeline to avoid endorsing self-description. **To hard-deny tools, use tool allowlists or hooks**—annotations are only for host-side identification and TUI display.
`idempotentHint` and `title` are currently not consumed by the SDK—passing them won't error, but the SDK neither consumes nor echoes them to the host. Maintain your own mapping if your app needs them.
> 💡 **About `maxResultSizeChars`**: the Python SDK writes `anthropic/maxResultSizeChars` into the tool's `_meta` via `ToolAnnotations(maxResultSizeChars=...)`, letting the CLI relax the default 50K output limit (TS exposes the same annotation; the wire format is identical).
#### `CallToolResult` Structure
```typescript TypeScript
type CallToolResult = {
content: Array<
| { type: 'text'; text: string }
| { type: 'image'; data: string; mimeType: string } // base64
| { type: 'audio'; data: string; mimeType: string }
| { type: 'resource'; resource: { uri: string; text?: string; blob?: string; mimeType?: string } }
| { type: 'resource_link'; uri: string; title?: string; name?: string }
>;
isError?: boolean; // when true, the AI sees this as a failed result
};
```
```python Python
# Success return
{"content": [{"type": "text", "text": "result"}]}
# Business failure: use is_error instead of throwing an exception
{"content": [{"type": "text", "text": "error description"}], "is_error": True}
```
**Use the error flag (`isError: true` / `is_error: True`) for business failures** instead of throwing—an exception kills the whole tool call and the AI gets nothing, while the error flag tells the AI "this call failed, try something else". For the Python/TS behavioral differences (`resource_link` degraded to text, top-level `_meta` not passed through, etc.) see [Tools](/cli/sdk/tools).
```typescript TypeScript
const queryDb = tool(
'query_db',
'Read-only SQL query.',
{ sql: z.string() },
async ({ sql }) => {
if (!/^\s*SELECT/i.test(sql)) {
return {
isError: true,
content: [{ type: 'text', text: 'Only SELECT statements are allowed' }],
};
}
const rows = await db.query(sql);
return { content: [{ type: 'text', text: JSON.stringify(rows) }] };
},
{ annotations: { readOnlyHint: true } },
);
```
```python Python
@tool(
"query_db",
"Read-only SQL query.",
{"sql": Annotated[str, "SQL query statement"]},
annotations=ToolAnnotations(readOnlyHint=True),
)
async def query_db(args):
sql = args["sql"]
if not sql.lstrip().upper().startswith("SELECT"):
return {
"is_error": True,
"content": [{"type": "text", "text": "Only SELECT statements are allowed"}],
}
rows = await db.query(sql)
return {"content": [{"type": "text", "text": json.dumps(rows)}]}
```
### Handler cancellation signal (Python)
Python handlers may accept a second parameter, `ToolInvocationContext`, and exit cooperatively via `extra.signal` when the CLI cancels the in-flight call:
```python Python
@tool("watch", "Watch a counter", {"max": int})
async def watch(args, extra):
for i in range(args["max"]):
if extra.signal.is_set():
return {"content": [{"type": "text", "text": f"aborted at {i}"}]}
await asyncio.sleep(0.01)
return {"content": [{"type": "text", "text": "done"}]}
```
---
## Stdio Server
Communicates with MCP servers via a child process's stdin/stdout. The `@modelcontextprotocol/server-*` packages on NPM are all stdio implementations.
```typescript TypeScript
type McpStdioServerConfig = {
type?: 'stdio'; // optional; stdio is the default
command: string; // executable command
args?: string[]; // command arguments
env?: Record; // environment variables
isProxy?: boolean; // proxy flag (aggregates multiple backends)
};
const q = query({
prompt: 'Read the title from the project README',
options: {
mcpServers: {
fs: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '/path/to/project'],
},
gh: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-github'],
env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! },
},
},
},
});
```
```python Python
class McpStdioServerConfig(TypedDict):
type: NotRequired[Literal["stdio"]] # optional; stdio is the default
command: str # executable command
args: NotRequired[list[str]] # command arguments
env: NotRequired[dict[str, str]] # environment variables
tools: NotRequired[list[McpServerToolPolicy]]
options = QoderAgentOptions(
mcp_servers={
"fs": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/project"],
},
"gh": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {"GITHUB_TOKEN": os.environ["GITHUB_TOKEN"]},
},
},
)
```
An unreachable or failing `command` doesn't drag down the whole query—that server's status stays non-`'connected'` and other servers are unaffected.
---
## SSE / HTTP Server
```typescript TypeScript
type McpSSEServerConfig = {
type: 'sse';
url: string;
headers?: Record;
isProxy?: boolean;
};
type McpHttpServerConfig = {
type: 'http'; // Streamable HTTP
url: string;
headers?: Record;
isProxy?: boolean;
};
const q = query({
prompt: 'Query this month\'s sales data',
options: {
mcpServers: {
analytics: {
type: 'http',
url: 'https://analytics.example.com/mcp',
headers: { Authorization: `Bearer ${process.env.ANALYTICS_TOKEN}` },
},
},
},
});
```
```python Python
class McpSSEServerConfig(TypedDict):
type: Literal["sse"]
url: str
headers: NotRequired[dict[str, str]]
tools: NotRequired[list[McpServerToolPolicy]]
class McpHttpServerConfig(TypedDict):
type: Literal["http"] # Streamable HTTP
url: str
headers: NotRequired[dict[str, str]]
tools: NotRequired[list[McpServerToolPolicy]]
options = QoderAgentOptions(
mcp_servers={
"analytics": {
"type": "http",
"url": "https://analytics.example.com/mcp",
"headers": {"Authorization": f"Bearer {os.environ['ANALYTICS_TOKEN']}"},
},
},
)
```
Likewise, an unreachable remote URL won't hang the query; the server status stays non-`'connected'`, and other servers are unaffected. For remote services requiring OAuth, see [OAuth Authentication](#oauth-authentication).
---
## Tool Naming and Allowlists
The CLI uniformly prefixes MCP tools when exposing them to the model:
```
mcp____
```
For example, server `my_tools` with tool `greet` appears to the model as `mcp__my_tools__greet`. Server names may contain hyphens and other special characters (`my-tools` → `mcp__my-tools__`).
### `tools`: Restrict Which Tools the Model Can See
Use `tools` when you want the model to **only see a subset of tools**. The CLI adds every built-in tool not in the list to the disallow set — effectively a visibility allowlist:
```typescript TypeScript
options: {
mcpServers: { my_tools: server },
tools: [
'Read', 'Grep', // built-in tools you still want
'mcp__my_tools__greet',
'mcp__my_tools__search_docs',
],
}
```
```python Python
options = QoderAgentOptions(
mcp_servers={"my_tools": server},
tools=[
"Read", "Grep", # built-in tools you still want
"mcp__my_tools__greet",
"mcp__my_tools__search_docs",
],
)
```
> ⚠️ **Omitting `tools` means everything is exposed**: all built-in tools plus every tool from connected MCP servers reach the model. For production, list them explicitly to tighten scope.
### Pre-approval list (**not** a visibility allowlist)
`allowedTools` / `allowed_tools` adds the listed tools to the auto-approve rules—invocations **skip the permission prompt**, but unlisted tools are **not** hidden. Commonly used to exempt low-risk MCP tools from approval:
```typescript TypeScript
options: {
mcpServers: { my_tools: server },
allowedTools: [
'mcp__my_tools__greet', // pre-approved, no prompt
'mcp__my_tools__search_docs',
],
}
```
```python Python
options = QoderAgentOptions(
mcp_servers={"my_tools": server},
allowed_tools=[
"mcp__my_tools__greet", # pre-approved, no prompt
"mcp__my_tools__search_docs",
],
)
```
Omitting the pre-approval list only means no pre-approval rules—the model can still see/call all tools; write operations just go through approval per the permission mode. Full semantics in the [Permissions docs](/cli/sdk/permissions).
### Process-type server allowlist
`allowedMcpServerNames` / `allowed_mcp_server_names` filters **process-type** (stdio/sse/http) servers only and **does not affect in-process servers**. Combine with `strictMcpConfig: true` / `strict_mcp_config=True` to stop the CLI from loading extra local configs:
```typescript TypeScript
options: {
mcpServers: {
keep: makeStdioConfig('...'),
drop: makeStdioConfig('...'),
},
allowedMcpServerNames: ['keep'], // 'drop' still appears in status but does not connect
strictMcpConfig: true, // skip loading MCP servers from settings.json / .mcp.json
}
```
```python Python
options = QoderAgentOptions(
mcp_servers={
"keep": {"command": "..."},
"drop": {"command": "..."},
},
allowed_mcp_server_names=["keep"], # 'drop' still appears in status but does not connect
strict_mcp_config=True, # do not load MCP servers from settings.json / .mcp.json
)
```
> ⚠️ **Omitting the allowlist opens everything up**: all declared process-type servers connect; list names explicitly to narrow. In-process servers are never affected by this field.
---
## Runtime management
In TypeScript, runtime management goes through the `Query` object returned by `query()`; in Python, the one-shot `query()` iterator cannot change servers or auth mid-flight—use `QoderSDKClient`. All methods talk to the CLI over the control channel and are async and idempotent.
> ⚠️ **Caching principle**: MCP server config / auth changes rebuild the tools list, and **mid-session changes break the prompt prefix cache**. The SDK provides "query status + finish auth before the first message" methods; configure the server set once at startup via options and restart the session when it must change.
### Querying Status
```typescript TypeScript
const status = await q.mcpServerStatus();
// Returns McpServerStatus[], each item includes:
// { name, status: 'pending' | 'connecting' | 'connected' | 'failed' | 'needs-auth' | 'disabled', tools?, ... }
for (const s of status) {
console.log(`${s.name}: ${s.status}`);
if (s.status === 'connected') {
console.log(' tools:', s.tools?.map((t) => t.name));
}
}
```
```python Python
async with QoderSDKClient(options) as client:
status = await client.get_mcp_status()
# Returns McpStatusResponse: {"mcpServers": [McpServerStatus, ...]}
for server in status["mcpServers"]:
print(f"{server['name']}: {server['status']}")
if server["status"] == "connected":
print(" tools:", [t["name"] for t in server.get("tools", [])])
```
> 💡 The MCP handshake happens after the CLI completes `initialize` and before the first user message. Query status only after the initialization result returns—handshake IO can take hundreds of milliseconds, so poll until `connected` before relying on it.
### Subscribing to Status Changes
- **TypeScript**: MCP status is **pull**, not push—call `await q.mcpServerStatus()`, polling in your own code as needed.
- **Python**: besides pulling, you can attach an `on_mcp_status_change` callback in options, invoked once per status change; or consume the message stream filtering `system/mcp_status_change`. Callback and stream carry the same payload.
```python Python
async def on_status(msg):
print(f"{msg['server_name']} -> {msg['status']}")
if msg.get("error"):
print(" error:", msg["error"])
options = QoderAgentOptions(
mcp_servers={...},
on_mcp_status_change=on_status,
)
```
### Changing the server set
To keep the prompt prefix cache stable, **prefer** finalizing server-set changes at startup:
| Goal | TypeScript | Python |
| ------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| Add / remove / replace servers | Configure in `options.mcpServers`; restart `query()` to change the set | Configure `mcp_servers` at startup; at runtime `client.set_mcp_servers(servers)` replaces wholesale (returns `{added, removed, errors}`) |
| Enable only some process-type servers | `allowedMcpServerNames` allowlist | `allowed_mcp_server_names` allowlist |
| Reconnect a server | Restart `query()` | `client.reconnect_mcp_server(name)`, typically to recover from `'failed'` |
| Enable / disable a server | Restart `query()` | `client.toggle_mcp_server(name, enabled)`; disabling disconnects and delists its tools |
| Sign out of a server | Restart `query()` without the token | `client.mcp_clear_auth(name)` |
> ⚠️ These Python runtime methods all rebuild the tools list and therefore break the prompt prefix cache. In production, prefer configuring everything at startup and reserve these APIs for debugging and local development.
### Controlling Request Timeout
```typescript TypeScript
options: {
controlRequestTimeoutMs: 20_000, // default 60_000; pass 0 to disable
}
```
```python Python
options = QoderAgentOptions(
control_request_timeout_ms=20_000, # default 60_000; pass 0 to disable
)
```
On timeout the SDK automatically writes a `control_cancel_request` and rejects the pending request.
---
## OAuth Authentication
Remote MCP servers (HTTP/SSE) often require OAuth. The CLI has a complete built-in OAuth 2.0 + PKCE + Dynamic Client Registration (RFC 7591) implementation.
> ⚠️ **Caching principle**: after OAuth completes, the CLI reconnects the server and rediscovers tools—**finishing auth mid-session inevitably breaks the prompt prefix cache**. Complete auth **before** the first user message and start chatting once the tools list is stable.
> 💡 **This section covers CLI-driven OAuth only**: the CLI does metadata discovery, PKCE, token exchange, and token persistence itself. There is a separate **server-driven** auth path—the server uses MCP `elicitation/create` to send the client to a URL to authorize (typical example: GitHub MCP). The two paths are independent and never trigger together. See [Elicitation: server requests user input](#elicitation-server-requests-user-input).
### Host-driven authentication (outbound)
The host controls OAuth timing, completing it **before** sending the first user message:
```typescript TypeScript
const q = query({
prompt: userMessages(), // AsyncIterable — no message is sent yet
options: {
mcpServers: {
// Assume this remote server uses the CLI-driven standard OAuth (metadata discovery + PKCE).
// If you connect to a server like GitHub MCP that implements OAuth on its own side, use onElicitation instead.
analytics: { type: 'http', url: 'https://analytics.example.com/mcp' },
},
},
});
// Wait for handshake to complete
await q.initializationResult();
// Find servers that need authentication
const status = await q.mcpServerStatus();
for (const s of status.filter((x) => x.status === 'needs-auth')) {
const result = await q.mcpAuthenticate(s.name);
if (result.requiresUserAction) {
await openInBrowser(result.authUrl!);
const callbackUrl = await waitForUserPasteCallback();
await q.mcpSubmitOAuthCallbackUrl(s.name, callbackUrl);
}
// Silent path (cached client + valid refresh token): result.requiresUserAction === false
// No UI prompt needed; just proceed to the next step.
}
// At this point the tools list is stable; sending the first user message
// will let the prompt prefix cache be established cleanly.
for await (const msg of q) { /* ... */ }
```
```python Python
async with QoderSDKClient(options) as client:
status = await client.get_mcp_status()
for server in status["mcpServers"]:
if server["status"] != "needs-auth":
continue
result = await client.mcp_authenticate(server["name"])
if result.get("requiresUserAction"):
await open_in_browser(result["authUrl"])
callback_url = await wait_for_user_paste_callback()
await client.mcp_submit_oauth_callback_url(server["name"], callback_url)
# Silent path (cached client + valid refresh token): requiresUserAction=False
# No UI needed; the server transitions directly to connected
# The tools list is now stable; safe to send user messages
await client.query("first user message")
```
| Method (TypeScript / Python) | Purpose | When to call |
| -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| `mcpAuthenticate(name, redirectUri?)` / `mcp_authenticate(name, redirect_uri=None)` | Starts OAuth; returns `{ authUrl?, requiresUserAction }`. On silent renewal `requiresUserAction: false`—no UI needed | **Before the first user message** |
| `mcpSubmitOAuthCallbackUrl(name, url)` / `mcp_submit_oauth_callback_url(name, callback_url)` | Submits the full callback URL (with code/state) | **Before the first user message** |
| `inject_mcp_token(name, token)` (Python only) | Host runs the whole OAuth itself and injects the `OAuthToken` into the CLI | **Before the first user message** |
| `mcp_clear_auth(name)` (Python only) | Deletes the CLI-stored OAuth credentials—"sign out" | Anytime; the next tool call triggers re-auth |
`redirectUri` / `redirect_uri` is optional and overrides the default OAuth callback target (Electron custom protocols, intranet callback addresses, etc.).
The CLI stores tokens in the system Keychain by default (macOS / Linux Secret Service), falling back to `~/.qoder/mcp-oauth-tokens.json` (0o600 permissions + cross-process locking).
### Inbound: the `on_mcp_oauth_required` callback (Python)
The Python SDK also supports an inbound path: when the CLI detects during handshake that a server needs OAuth, it pushes an `McpOAuthRequest` to the SDK via control\_request, and the SDK invokes the host's `on_mcp_oauth_required` callback. The host returns one of these resolutions:
| Return type | Meaning |
| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `OAuthToken` or `{"token": OAuthToken}` | The host runs the entire OAuth flow itself and injects the token directly into the CLI |
| `{"callbackUrl": "..."}` | The host returns the full callback URL (including `code` / `state`); the CLI parses it and exchanges for a token |
| `{"code": "...", "state": "..."}` | The host extracts the code itself and returns it to the CLI |
| `None` | Reject; the CLI marks that server as failed |
```python Python
async def handle_oauth(request: McpOAuthRequest) -> McpOAuthResolution | None:
# Open request['auth_url'] in an Electron BrowserWindow / system browser
callback_url = await open_browser_and_wait_for_callback(request["auth_url"])
return {"callbackUrl": callback_url}
options = QoderAgentOptions(
mcp_servers={"analytics": {"type": "http", "url": "https://analytics.example.com/mcp"}},
on_mcp_oauth_required=handle_oauth,
control_request_timeout_ms=120_000, # user authorization may take a while
)
```
---
## Elicitation: Server Requests User Input
MCP `elicitation/create` is a **server → client** request for showing the user an interaction. The SDK surfaces it to the host via `onElicitation` (TypeScript) / `on_elicitation` (Python).
### Two Modes
| Mode | Trigger Scenario | Typical Use |
| -------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| `'form'` | The server wants structured input; the request carries `requestedSchema` (a restricted-subset MCP JSON Schema) | API key entry, config forms, confirmations |
| `'url'` | The server sends the user to a URL; the request carries `url` + `elicitationId` | Server-side OAuth, device-code activation, account linking |
URL mode completes asynchronously: once the server's own callback receives the user's authorization it sends `notifications/elicitation/complete`—the SDK projects it as an elicitation-complete message in the stream.
> ⚠️ qodercli currently advertises only `elicitation: {}` in MCP capabilities (equivalent to `{ form: {} }`), so **only form mode actually reaches the client from remote servers today**. URL mode is protocol-complete but requires the CLI to declare the `elicitation.url` capability—coming with future CLI versions, at which point the path lights up automatically.
### Callback Signature
```typescript TypeScript
import type { OnElicitation, ElicitationRequest, ElicitationResult } from '@qoder-ai/qoder-agent-sdk';
type OnElicitation = (
request: ElicitationRequest,
options: { signal: AbortSignal },
) => Promise;
type ElicitationRequest = {
serverName: string; // name of the MCP server that issued the request
message: string; // explanation shown to the user
mode?: 'form' | 'url'; // defaults to form
url?: string; // required when mode='url'
elicitationId?: string; // required when mode='url'; used to correlate later completion notifications
requestedSchema?: Record; // field schema carried when mode='form'
title?: string;
displayName?: string;
description?: string;
};
type ElicitationResult = {
action: 'accept' | 'decline' | 'cancel';
content?: Record; // populated when accept + form
};
```
```python Python
from qoder_agent_sdk import ElicitationRequest, ElicitationResult, QoderAgentOptions
async def on_elicitation(req: ElicitationRequest) -> ElicitationResult:
# Form mode: req["requestedSchema"] is a JSON Schema; the returned content must match.
if req.get("mode") == "form":
return {"action": "accept", "content": {"token": "xxx"}}
# Return decline / cancel for any case you cannot handle; the CLI relays the result back to the MCP server.
return {"action": "decline"}
options = QoderAgentOptions(
mcp_servers={"my_server": {"type": "http", "url": "..."}},
on_elicitation=on_elicitation,
)
```
Python notes:
- Field names follow the TS SDK's camelCase (`serverName / elicitationId / requestedSchema / displayName`); the CLI's snake\_case payload is converted automatically by the SDK.
- Returning `None` equals `{"action": "cancel"}`; with no callback registered the SDK auto-answers cancel per the default contract.
- You can also return a `mcp.types.ElicitResult` Pydantic model (the SDK calls `model_dump`).
In TypeScript, `signal` aborts on `q.close()` / interruption—check it in long flows.
### Form Mode Example
```typescript TypeScript
const q = query({
prompt: userMessages(),
options: {
mcpServers: { my_server: { type: 'http', url: '...' } },
onElicitation: async (request) => {
if (request.mode !== 'url' && request.requestedSchema) {
// Show a form in the UI and collect the user's input
const filled = await showForm(request.message, request.requestedSchema);
if (!filled) return { action: 'cancel' };
return { action: 'accept', content: filled };
}
return { action: 'decline' };
},
},
});
```
```python Python
async def on_elicitation(req: ElicitationRequest) -> ElicitationResult:
if req.get("mode") != "url" and req.get("requestedSchema"):
# Show a form in the UI and collect the user's input
filled = await show_form(req["message"], req["requestedSchema"])
if not filled:
return {"action": "cancel"}
return {"action": "accept", "content": filled}
return {"action": "decline"}
```
### URL mode example (with elicitation\_complete)
```typescript TypeScript
const q = query({
prompt: userMessages(),
options: {
mcpServers: { gh: { type: 'http', url: 'https://mcp.github.com/mcp' } },
onElicitation: async (request, { signal }) => {
if (request.mode !== 'url' || !request.url) {
return { action: 'cancel' };
}
// Open the browser so the user can authorize; we only acknowledge "I have started the flow"
// Real completion is signaled by notifications/elicitation/complete from the server side
await openInBrowser(request.url);
return { action: 'accept' };
},
},
});
// Listen for system/elicitation_complete to learn when server-side authorization is done
for await (const msg of q) {
if (msg.type === 'system' && msg.subtype === 'elicitation_complete') {
console.log(`server '${msg.mcp_server_name}' finished elicitation ${msg.elicitation_id}`);
// The server now has its token; subsequent tool calls can succeed directly.
}
}
```
> 💡 **Do not await the browser round-trip inside the elicitation callback.** URL mode is designed for the callback to `accept` immediately (= the user has started the flow) so the CLI doesn't block the control channel; the real completion signal is the subsequent `elicitation_complete` message. Awaiting the whole OAuth redirect triggers the control request timeout.
### Boundary with the OAuth Path
- **CLI-driven OAuth** (`mcpAuthenticate` / `mcp_authenticate`, etc.): tokens land in the qodercli Keychain; driven by MCP status showing `needs-auth`; **does not trigger** the elicitation callback.
- **Server-driven elicit URL**: tokens stay inside the server; MCP status never shows `needs-auth`; handled by the elicitation callback and finalized by the `elicitation_complete` message.
The two paths don't conflict but don't overlap either: a given server usually takes exactly one. Not sure which one a server uses? Watch whether it sends `elicitation/create` during handshake—if it does, it's server-driven.
### Hook Channel
Hosts can also attach hooks to observe / intercept elicitation:
| Hook event | Timing | Notes |
| -------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Elicitation` | When the server request arrives | In TypeScript it takes precedence over `onElicitation` and can auto accept / decline / cancel (short-circuiting the UI) or pass through; in Python it is observe-only—decisions go to `on_elicitation` |
| `ElicitationResult` | After the user responds | TypeScript can rewrite `action` / `content` or block; Python observes only |
| `Notification` (type=`elicitation_complete`) | When the URL-mode completion notification arrives | Trigger IDE / system notifications |
```python Python
from qoder_agent_sdk import HookMatcher, QoderAgentOptions
async def on_elicit(input, tool_use_id, context):
print(
"elicit from",
input["mcp_server_name"],
"mode=",
input["mode"],
"schema=",
input.get("requested_schema"),
)
return {"continue_": True}
options = QoderAgentOptions(
mcp_servers={"my_server": {"type": "http", "url": "..."}},
hooks={
"Elicitation": [HookMatcher(hooks=[on_elicit])],
},
)
```
---
## Options Reference
| Field (TypeScript / Python) | Default | Description |
| -------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
| `mcpServers` / `mcp_servers` | – | Server name → config; Python also accepts a JSON config file path |
| `allowedMcpServerNames` / `allowed_mcp_server_names` | – | Process-type server allowlist (in-process unaffected); omitting opens everything |
| `strictMcpConfig` / `strict_mcp_config` | `false` | Stops the CLI from loading extra MCP servers from user config files |
| `tools` / `tools` | – | **Model-visible tool allowlist**; omitting exposes all built-in + MCP tools |
| `allowedTools` / `allowed_tools` | – | **Pre-approval** list (skips the permission prompt, does **not** control visibility); omitting means no pre-approval rules |
| `disallowedTools` / `disallowed_tools` | – | Explicitly denied tools; takes precedence over allow |
| `controlRequestTimeoutMs` / `control_request_timeout_ms` | `60_000` | Control request timeout (incl. the mcp series); 0 disables |
| `onElicitation` / `on_elicitation` | – | Fires when an MCP server requests user input (form / url modes) |
| `on_mcp_oauth_required` (Python only) | – | Fires when the CLI detects a server needs OAuth |
| `on_mcp_status_change` (Python only) | – | Fires on every server status change; equivalent to filtering the `system/mcp_status_change` stream |
### Runtime method quick reference
| Method (TypeScript / Python) | Description | When to call |
| ----------------------------------------------------------------------- | --------------------------------------------------------------------------- | --------------------------------- |
| `mcpServerStatus()` / `get_mcp_status()` | Get all current MCP server statuses | Anytime |
| `mcpAuthenticate(...)` / `mcp_authenticate(...)` | Start OAuth; returns `{ authUrl?, requiresUserAction }` | **Before the first user message** |
| `mcpSubmitOAuthCallbackUrl(...)` / `mcp_submit_oauth_callback_url(...)` | Submit the OAuth callback | **Before the first user message** |
| `set_mcp_servers(servers)` (Python only) | Replace the MCP server config wholesale; returns `{added, removed, errors}` | Anytime (breaks the prefix cache) |
| `reconnect_mcp_server(name)` (Python only) | Reconnect a server | Anytime |
| `toggle_mcp_server(name, enabled)` (Python only) | Enable / disable a server | Anytime |
| `inject_mcp_token(name, token)` (Python only) | Inject a token after host-run OAuth | **Before the first user message** |
| `mcp_clear_auth(name)` (Python only) | Delete stored OAuth credentials | Anytime |
> In TypeScript, change the server set via `options.mcpServers` (configured at startup) plus a `query()` restart.
---
## Type Reference
```typescript TypeScript
import type {
// Factory function return value
McpSdkServerConfigWithInstance,
// Union type — pass into options.mcpServers
McpServerConfig,
// Individual transport types
McpStdioServerConfig,
McpSSEServerConfig,
McpHttpServerConfig,
McpSdkServerConfig,
// Status
McpServerStatus,
McpServerStatusConfig,
// Elicitation
OnElicitation,
ElicitationRequest,
ElicitationResult,
SDKElicitationCompleteMessage,
} from '@qoder-ai/qoder-agent-sdk';
import { tool, createSdkMcpServer } from '@qoder-ai/qoder-agent-sdk';
import type {
AnyZodRawShape,
InferShape,
SdkMcpToolDefinition,
} from '@qoder-ai/qoder-agent-sdk';
```
```python Python
from qoder_agent_sdk import (
# Factories
create_sdk_mcp_server,
tool,
SdkMcpTool,
# Configs
McpServerConfig,
McpSdkServerConfig,
McpServerToolPolicy,
# Status
McpServerStatus,
McpServerStatusConfig,
McpServerConnectionStatus,
McpServerInfo,
McpToolInfo,
McpToolAnnotations,
McpStatusResponse,
McpStatusChangeMessage,
# Runtime changes
McpSetServersResult,
# OAuth
OAuthToken,
McpOAuthRequest,
McpOAuthResolution,
McpOAuthTokenResolution,
McpOAuthCallbackUrlResolution,
McpOAuthCodeResolution,
OnMcpOAuthRequired,
OnMcpStatusChange,
)
# Transport config TypedDicts are available from the types module
from qoder_agent_sdk.types import (
McpStdioServerConfig,
McpSSEServerConfig,
McpHttpServerConfig,
)
```
`McpServerStatus.status` enum:
| Value | Meaning |
| -------------- | -------------------------------------------------------------- |
| `'pending'` | Registered, connection not yet started |
| `'connecting'` | Handshaking |
| `'connected'` | Connected, tools are callable |
| `'failed'` | Connection failed (check the `error` field) |
| `'needs-auth'` | Requires OAuth, proceed with auth flow |
| `'disabled'` | Disabled (determined by CLI internal config or external state) |
---
## Best Practices
1. **Write descriptions for the AI**: a tool's `description` decides when the AI picks it. Spell out "what it does, when to use it, what not to use it for".
2. **Describe every field**: always add `.describe(...)` to Zod fields in TypeScript and `Annotated[type, "..."]` in Python—the AI uses these to construct call arguments.
3. **Fail with the error flag, don't throw**: let the AI see the result. Exceptions leave the model confused and may trigger retries.
4. **Prefer read-only + `readOnlyHint`**: be careful with writes; pair them with the permission callback or hooks for double confirmation.
5. **Keep server names short**: They appear in tool prefixes; overly long names waste tokens.
6. **Place in-process shared state in module scope**: Handlers are closures, but each query still reuses the same server instance.
7. **Finish OAuth before the first user message**: mid-session auth inevitably breaks the prompt prefix cache.
8. **Pull MCP status on demand**: poll `mcpServerStatus()` in TypeScript; in Python choose `get_mcp_status()` or the `on_mcp_status_change` callback.
9. **Set a sensible control request timeout**: remote server handshakes can take seconds—the default 60s usually suffices; raise it while waiting for OAuth user actions; set it explicitly in CI.
10. **Use strict MCP config for isolation**: keep MCP servers declared in the user's local `settings.json` / `.mcp.json` from interfering with your app.
---
## Complete Example
```typescript TypeScript
import { query, createSdkMcpServer, tool } from '@qoder-ai/qoder-agent-sdk';
import { z } from 'zod';
// 1. Define business tools
const getUserOrders = tool(
'get_user_orders',
'Query a user\'s orders, optionally filtered by status.',
{
userId: z.string().describe('User UUID'),
status: z.enum(['pending', 'paid', 'shipped', 'cancelled']).optional()
.describe('Filter by order status'),
},
async ({ userId, status }) => {
try {
const orders = await db.getOrders(userId, status);
return { content: [{ type: 'text', text: JSON.stringify(orders) }] };
} catch (err) {
return {
isError: true,
content: [{ type: 'text', text: `Query failed: ${(err as Error).message}` }],
};
}
},
{ annotations: { readOnlyHint: true } },
);
// 2. Assemble the server
const myServer = createSdkMcpServer({
name: 'crm',
tools: [getUserOrders /* , ... */],
});
// 3. Start query (use AsyncIterable so no message is sent yet)
async function* userMessages() {
yield {
type: 'user' as const,
message: { role: 'user' as const, content: 'List the recently paid orders for user-123' },
parent_tool_use_id: null,
};
}
const q = query({
prompt: userMessages(),
options: {
mcpServers: {
crm: myServer,
// Assume a remote server that uses CLI-driven OAuth (GitHub MCP uses elicit-URL, not this path)
analytics: { type: 'http', url: 'https://analytics.example.com/mcp' },
},
allowedTools: ['mcp__crm__get_user_orders'],
controlRequestTimeoutMs: 30_000,
},
});
// 4. Wait for handshake; actively drive auth before the first user message
await q.initializationResult();
const status = await q.mcpServerStatus();
for (const s of status.filter((x) => x.status === 'needs-auth')) {
const result = await q.mcpAuthenticate(s.name);
if (result.requiresUserAction) {
const callbackUrl = await openInBrowserAndWaitForCallback(result.authUrl!);
await q.mcpSubmitOAuthCallbackUrl(s.name, callbackUrl);
}
// Silent refresh success: requiresUserAction === false; no UI required
}
// 5. Consume messages (tools list is now stable; prompt prefix cache will be established correctly)
for await (const msg of q) {
if (msg.type === 'result') {
console.log(msg.subtype === 'success' ? msg.result : msg);
break;
}
}
await q.close?.();
```
```python Python
import asyncio
import json
import os
from typing import Annotated
from mcp.types import ToolAnnotations
from qoder_agent_sdk import (
AssistantMessage,
McpOAuthRequest,
McpOAuthResolution,
QoderAgentOptions,
QoderSDKClient,
ResultMessage,
TextBlock,
create_sdk_mcp_server,
tool,
)
# 1. Define application tools
@tool(
"get_user_orders",
"Query a user's orders, optionally filtered by status.",
{
"user_id": Annotated[str, "User UUID"],
"status": Annotated[str, "Filter by order status: pending/paid/shipped/cancelled"],
},
annotations=ToolAnnotations(readOnlyHint=True),
)
async def get_user_orders(args):
try:
orders = await db.get_orders(args["user_id"], args.get("status"))
return {"content": [{"type": "text", "text": json.dumps(orders)}]}
except Exception as e:
return {
"is_error": True,
"content": [{"type": "text", "text": f"Query failed: {e}"}],
}
# 2. Assemble the server
crm = create_sdk_mcp_server(name="crm", tools=[get_user_orders])
# 3. Prepare the inbound OAuth callback (called by the CLI when a remote server requires auth)
async def handle_oauth(request: McpOAuthRequest) -> McpOAuthResolution | None:
callback_url = await open_browser_and_wait_for_callback(request["auth_url"])
return {"callbackUrl": callback_url}
# 4. Start the client; complete authentication before the first message
async def main():
options = QoderAgentOptions(
mcp_servers={
"crm": crm,
"analytics": {"type": "http", "url": "https://analytics.example.com/mcp"},
},
allowed_tools=["mcp__crm__get_user_orders"],
on_mcp_oauth_required=handle_oauth,
control_request_timeout_ms=120_000,
)
async with QoderSDKClient(options) as client:
# Outbound fallback: even when the CLI did not actively go inbound, pull status and drive auth ourselves
status = await client.get_mcp_status()
for server in status["mcpServers"]:
if server["status"] != "needs-auth":
continue
result = await client.mcp_authenticate(server["name"])
if result.get("requiresUserAction"):
callback_url = await open_browser_and_wait_for_callback(result["authUrl"])
await client.mcp_submit_oauth_callback_url(server["name"], callback_url)
# 5. Consume messages (the tools list is now stable; the prefix cache will be established correctly)
await client.query("Find user-123's recent paid orders")
async for msg in client.receive_response():
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
print(block.text)
elif isinstance(msg, ResultMessage):
if msg.subtype == "success":
print("done, cost=", msg.total_cost_usd)
else:
print("failed:", msg.subtype)
asyncio.run(main())
```
# Subagents
Subagents are specialized roles that the main session can delegate to temporarily. The Qoder Agent SDK supports two kinds of subagents:
- **Built-in subagents**: Provided by qodercli, such as general search, code exploration, planning, and related roles.
- **Custom subagents**: Defined by SDK users through `options.agents`, suitable for business review, test execution, security analysis, and other specialized roles.
This guide focuses on using built-in subagents from the SDK and defining custom subagents when needed. You can read it from top to bottom or jump to a specific configuration item. For complete type definitions, see [Agents Reference](/cli/sdk/references).
Unless stated otherwise, "Agent" in this page means a subagent the main session can delegate to; `options.agent` is the special usage that runs a subagent definition as the main-session role.
## Built-in Subagents
When using a built-in subagent, you do not need to write the subagent definition yourself. You only need to know its name and reference it from the SDK.
Common built-in subagents currently provided by qodercli:
| Name | Purpose |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `general-purpose` | General-purpose subagent, suitable for searching code, researching complex problems, and executing multi-step tasks |
| `Explore` | Read-only code exploration subagent, suitable for quickly finding files, searching keywords, and understanding code structure |
| `Plan` | Read-only planning subagent, suitable for designing implementation plans, identifying key files, and analyzing architectural tradeoffs |
The built-in subagent list can change with the qodercli version and current configuration. In the interactive CLI, enter `/agents` to view the currently discovered subagents. From the command line, you can also run:
```bash
qodercli agents list
```
After the SDK session initializes, you can read the subagents actually available in the current session:
```typescript TypeScript
import { query } from '@qoder-ai/qoder-agent-sdk';
const q = query({ prompt: 'List available agents.' });
const agents = await q.supportedAgents();
```
```python Python
from qoder_agent_sdk import QoderSDKClient, QoderAgentOptions
client = QoderSDKClient(options=QoderAgentOptions())
await client.connect("List available agents.")
agents = client.supported_agents()
await client.disconnect()
```
The returned list includes subagents registered via `options.agents` as well as built-in, user, project, and plugin subagents the CLI has discovered that apply to SDK scenarios. `general-purpose`, `Explore`, and `Plan` can appear in SDK sessions by default; the interactive-CLI helpers `qoder-guide` and `statusline-setup` are not supported in SDK sessions and won't appear in the results. See [AgentInfo](/cli/sdk/references) for the structure.
---
## Using Built-in Subagents
### Run as the Main Session Role
If you want the whole session to run under a built-in subagent role, pass the built-in subagent name directly to `options.agent`. You do not need to redefine it in `options.agents`.
```typescript TypeScript
import { query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Summarize this project architecture and identify the most important modules.',
options: {
agent: 'general-purpose',
},
});
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, query
options = QoderAgentOptions(agent="general-purpose")
async for message in query(
prompt="Summarize this project architecture and identify the most important modules.",
options=options,
):
print(message)
```
`options.agent` can reference a subagent registered by the SDK, or a built-in, user, project, or plugin subagent discovered by the current CLI and suitable for SDK sessions.
### Delegate as a Subagent
Subagent delegation happens through the built-in `Agent` tool. The main session's available tool set must include `Agent`; otherwise the model has no entry point for delegation. In SDK usage, a common pattern is to pre-authorize that tool call path and name the desired subagent in the prompt.
```typescript TypeScript
const q = query({
prompt: 'Use the Explore agent to find where authentication is implemented.',
options: {
// Pre-authorize Agent tool calls. If options.tools restricts the tool set, include 'Agent' there too.
allowedTools: ['Agent'],
},
});
```
```python Python
options = QoderAgentOptions(
allowed_tools=["Agent"],
)
async for message in query(
prompt="Use the Explore agent to find where authentication is implemented.",
options=options,
):
print(message)
```
`allowedTools: ['Agent']` / `allowed_tools=["Agent"]` pre-approves this class of tool calls; if you also narrow the main session's tool set with `options.tools`, include `Agent` there too. Never put `Agent` in the denylist.
Subagent names must match the current discovery results, including case. Current built-in names include `Explore`, `Plan`, and `general-purpose`. When unsure, read the supported subagent list first.
---
## Custom Subagents
When built-in subagents do not fit your business or project constraints, define custom subagents with `options.agents`. For example:
- Read-only code review subagent: can only read files and search, and cannot modify code.
- Test execution subagent: can run test commands and analyze failure reasons.
- Security review subagent: focuses only on authentication, authorization, injection, sensitive information leakage, and related risks.
- Business support subagent: can only call specific MCP tools, such as order lookup, ticket search, or internal knowledge base search.
Custom subagents usually involve three steps:
1. Define the subagent name, usage description, and system prompt in `options.agents`.
2. Narrow the tools it can use with `tools` or `disallowedTools`.
3. Let the main session delegate to it through the `Agent` tool, or use `options.agent` to let it drive the main session directly.
> **The `Agent` tool is required**: custom subagents are delegated to via the built-in `Agent` tool, so the tool allowlist must include `Agent`.
---
## Defining Custom Subagents with options.agents
Minimal example: register a read-only code review subagent.
```typescript TypeScript
import { query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Use the code-reviewer agent to review the authentication module.',
options: {
// Pre-authorize Agent tool calls. If options.tools restricts the tool set, include 'Agent' there too.
allowedTools: ['Agent'],
agents: {
'code-reviewer': {
description:
'Reviews code for correctness, security issues, and maintainability problems.',
prompt: `You are a code review specialist.
Review the requested code and report concrete findings.
Sort findings by severity and include file paths when possible.`,
tools: ['Read', 'Grep', 'Glob'],
},
},
},
});
for await (const message of q) {
// Consume streamed messages according to your application needs.
}
```
```python Python
import asyncio
from qoder_agent_sdk import AgentDefinition, QoderAgentOptions, query
async def main():
options = QoderAgentOptions(
allowed_tools=["Agent"],
agents={
"code-reviewer": AgentDefinition(
description=(
"Reviews code for correctness, security issues, and "
"maintainability problems."
),
prompt="""You are a code review specialist.
Review the requested code and report concrete findings.
Sort findings by severity and include file paths when possible.""",
tools=["Read", "Grep", "Glob"],
),
},
)
async for message in query(
prompt="Use the code-reviewer agent to review the authentication module.",
options=options,
):
print(message)
asyncio.run(main())
```
There are three key points in this example:
- `options.agents` registers the custom subagent available to this session.
- Subagent delegation happens through the `Agent` tool; that call path must be pre-approved here.
- The subagent's own `tools` only allow reading and searching, so it cannot edit files or execute commands.
### `options.agents` Input
`options.agents` maps subagent names to subagent definitions. Full type in [AgentDefinition](/cli/sdk/references).
| Field | Type | Required | How to set it | Description |
| ----------------- | ---------------------- | -------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `description` | `string` | Yes | One sentence describing when to use this subagent | Routing description for the model; affects whether it is invoked |
| `prompt` | `string` | Yes | The subagent's role, boundaries, and output requirements | System prompt for this subagent |
| `tools` | `string[]` | No | For example `['Read', 'Grep', 'Glob']` | Tool allowlist; when set, only listed tools can be used |
| `disallowedTools` | `string[]` | No | For example `['Bash', 'Write']` | Tool blocklist, useful when excluding only a few tools |
| `model` | `string` | No | For example `'inherit'`, `'auto'`, `'performance'` | Model configuration for the subagent |
| `maxTurns` | `number` | No | For example `8` | Limits how many turns the subagent may execute |
| `effort` | `EffortLevel` | No | For example `'low'`, `'medium'`, `'high'`, `'max'` | Controls reasoning effort |
| `permissionMode` | `PermissionMode` | No | For example `'default'`, `'acceptEdits'`, `'plan'` | Controls the permission mode for tool calls inside the subagent |
| `skills` | `string[]` | No | For example `['review']` | Skills preloaded into the subagent context |
| `mcpServers` | `AgentMcpServerSpec[]` | No | MCP server names or configurations | Limits or adds MCP servers for the subagent |
| `initialPrompt` | `string` | No | First-turn automatic input | Only takes effect when this subagent becomes the main session role through `options.agent` |
> **Python note**: `AgentDefinition` field names use protocol-style camelCase—`disallowedTools`, `maxTurns`, `initialPrompt`, `permissionMode`—not `disallowed_tools`, `max_turns`.
---
## Configuring the Subagent Role
`description` and `prompt` are the two most important fields for a custom subagent.
### `description`
`description` says "when this subagent should be used". The model uses it to decide whether to delegate.
```
description: 'Runs project tests, analyzes failing output, and suggests fixes.'
```
A good `description` should state the task boundary clearly. Avoid generic descriptions such as `A helpful agent` or `Helper`.
### `prompt`
`prompt` defines the subagent's role, boundaries, and output style. TypeScript type-checking fails without `prompt`; Python's `AgentDefinition` constructor requires it as well.
```
prompt: `You are a code review specialist.
Only review the requested code; do not edit files.
Return findings sorted by severity, with file paths and suggested fixes.`
```
If `prompt` is just a generic "you are a helpful assistant", the model may still call the subagent, but it will behave like an ordinary assistant: unclear on what to check first, what to avoid, and how to return results.
At minimum, `prompt` should explain three things:
| What to explain | Example |
| --------------------- | ------------------------------------------------------ |
| What task it owns | `Review code for security and maintainability issues.` |
| What it should not do | `Do not edit files. Do not run commands.` |
| How to return results | `Return findings sorted by severity with file paths.` |
---
## Configuring Model and Reasoning
First make `description` and `prompt` clear, then consider `model`, `effort`, and `maxTurns`. The former decides whether the subagent is invoked correctly and whether it understands its boundaries. The latter mainly tunes quality, speed, and cost after the role is clear.
| Option | Controls | When to adjust first |
| ---------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `model` | Selects the subagent's model tier | The subagent handles a fixed task type long-term and needs stable control over capability and cost |
| `effort` | How much reasoning budget to spend under the same model | The same subagent occasionally receives a more complex task that needs more careful reasoning |
| `maxTurns` | The maximum number of turns | The task may explore too deeply or run too long, or you want a hard cost limit |
Use this order of judgment:
1. Start with no setting, or set `model: 'inherit'`, so the subagent follows the main session model.
2. For frequent, simple, low-risk tasks, use `model: 'efficient'` or `model: 'lite'` to reduce cost.
3. For architecture design, complex refactors, cross-module reviews, and other high-risk tasks, use `model: 'performance'` or `model: 'ultimate'`.
4. If the model tier stays the same but you want the subagent to think more on the current task, increase `effort`.
5. If you are worried about runaway exploration, combine it with `maxTurns`.
Common combinations:
| Scenario | Recommended configuration | Description |
| ---------------------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------- |
| Quick Q\&A, format conversion, simple locating | `model: 'efficient'`, `effort: 'low'`, `maxTurns: 3` | Cheap and fast, suitable for low-risk tasks |
| Read-only code exploration and module mapping | `model: 'auto'` or `'inherit'`, `effort: 'medium'` | Let routing or the main session model decide the capability tier |
| Code review, security review, migration plan | `model: 'performance'`, `effort: 'high'` | Better for tasks that require careful tradeoffs and issue discovery |
| Complex system design and difficult analysis | `model: 'ultimate'`, `effort: 'high'` or `'max'` | Higher cost; recommended only for critical complex tasks |
| Batch helper subtasks | `model: 'efficient'`, `effort: 'low'`, smaller `maxTurns` | Helps control total cost in multi-subagent collaboration |
Example: give different subagents different strategies.
```typescript TypeScript
agents: {
explorer: {
description: 'Quickly searches code and summarizes relevant files.',
prompt: 'Find relevant files and return a concise summary. Do not edit.',
tools: ['Read', 'Grep', 'Glob'],
model: 'efficient',
effort: 'low',
maxTurns: 5,
},
architect: {
description: 'Designs complex implementation plans across modules.',
prompt: 'Analyze tradeoffs carefully and return an implementation plan with risks.',
tools: ['Read', 'Grep', 'Glob'],
model: 'performance',
effort: 'high',
maxTurns: 10,
},
}
```
```python Python
agents = {
"explorer": AgentDefinition(
description="Quickly searches code and summarizes relevant files.",
prompt="Find relevant files and return a concise summary. Do not edit.",
tools=["Read", "Grep", "Glob"],
model="inherit",
effort="low",
maxTurns=5,
),
"architect": AgentDefinition(
description="Designs complex implementation plans across modules.",
prompt="Analyze tradeoffs carefully and return an implementation plan with risks.",
tools=["Read", "Grep", "Glob"],
model="auto",
effort="high",
maxTurns=10,
),
}
```
See `model`, `maxTurns`, and `effort` in the [Agents Reference](/cli/sdk/references) for the full values.
---
## Controlling Subagent Tools
Custom subagents and the main session use the same tool names. Built-in tool names include `Read`, `Grep`, `Glob`, and `Bash`; custom MCP tools use the full format `mcp__{serverName}__{toolName}`. These settings decide which tools the subagent can see and call.
### The Main Session's `Agent` Tool
`options.agents` only registers subagents—it doesn't call them for the model. To delegate, the main session's tool set must contain `Agent`. The default tool set usually registers it; if you restrict tools with `options.tools`, remember to include `Agent`; putting `Agent` in the denylist disables delegation.
### Tool Allowlist: `tools`
`tools` is the subagent's tool allowlist. Once set, the subagent can only use listed tools.
```
tools: ['Read', 'Grep', 'Glob']
```
Common tool combinations:
| Scenario | Recommended tools | Description |
| ------------------- | --------------------------------------- | --------------------------------------------------------- |
| Read-only analysis | `Read`, `Grep`, `Glob` | Can inspect code; cannot modify files or run commands |
| Run tests | `Bash`, `Read`, `Grep` | Can execute test commands and analyze output |
| Write code | `Read`, `Edit`, `Write`, `Grep`, `Glob` | Can read and write files but cannot run commands directly |
| Call business tools | `mcp__server__tool` | Only allows specific custom tools |
### Tool Blocklist: `disallowedTools`
`disallowedTools` fits "allow most tools, exclude a few".
```
disallowedTools: ['Bash', 'Write']
```
Usually avoid setting both `tools` and `disallowedTools` unless you are certain of the final tool set.
### Relationship to Main Session Tool Configuration
A subagent's `tools` and `disallowedTools` only apply to that subagent. They do not inherit the main session's tool allowlist or blocklist trimming. Even if the main session only pre-authorizes the `Agent` delegation path, the subagent can still use its own configured `Read`, `Grep`, and related tools.
```typescript TypeScript
query({
prompt: 'Use the analyst agent to inspect the repository.',
options: {
// Pre-authorize the main session to call the Agent tool.
allowedTools: ['Agent'],
agents: {
analyst: {
description: 'Reads and summarizes code structure.',
prompt: 'Inspect relevant files and return a concise summary. Do not edit files.',
tools: ['Read', 'Grep', 'Glob'],
},
},
},
});
```
```python Python
options = QoderAgentOptions(
allowed_tools=["Agent"],
agents={
"analyst": AgentDefinition(
description="Reads and summarizes code structure.",
prompt="Inspect relevant files and return a concise summary. Do not edit files.",
tools=["Read", "Grep", "Glob"],
),
},
)
```
---
## Controlling Subagent Permissions
The tool set decides which tools a subagent *can call*; permission config decides how those calls are *approved or blocked*. `permissionMode` can be set per subagent to control the permission behavior of its internal tool execution.
```typescript TypeScript
agents: {
planner: {
description: 'Plans implementation work without making changes.',
prompt: 'Read relevant files and return an implementation plan. Do not edit files.',
tools: ['Read', 'Grep', 'Glob'],
permissionMode: 'plan',
},
}
```
```python Python
AgentDefinition(
description="Plans implementation work without making changes.",
prompt="Read relevant files and return an implementation plan. Do not edit files.",
tools=["Read", "Grep", "Glob"],
permissionMode="plan",
)
```
See the [Agents Reference](/cli/sdk/references) for the full set of `permissionMode` values and their meanings. If a tool needs user approval, use the session-level `canUseTool` / `can_use_tool` callback. The subagent ID is `context.agentID` in TypeScript and `context.agent_id` in Python. See [Approval and User Input](/cli/sdk/user-input#when-canusetool-runs) for the callback rules.
---
## Loading Skills for Subagents
`skills` preloads specialized skills for a subagent. It is useful when you want to bind a specific workflow, team convention, or tool usage pattern to one subagent instead of putting it in every prompt.
```typescript TypeScript
agents: {
reviewer: {
description: 'Reviews pull requests using the team review workflow.',
prompt: 'Review the requested changes and return actionable findings.',
tools: ['Read', 'Grep', 'Glob'],
skills: ['review'],
},
}
```
```python Python
AgentDefinition(
description="Reviews pull requests using the team review workflow.",
prompt="Review the requested changes and return actionable findings.",
tools=["Read", "Grep", "Glob"],
skills=["review"],
)
```
Recommendations:
| Scenario | How to configure |
| -------------------------------------------------- | --------------------------------------------------------------------- |
| The subagent always follows a specialized workflow | Put the corresponding skill in the subagent's `skills` |
| Only the main session needs a skill | Use session-level `options.skills`; do not put it in the subagent |
| A plugin-provided skill | Use the plugin-qualified name, for example `sdk-test-plugin:sdk-echo` |
Subagent `skills` only affect that subagent's context. They are not the same as main-session `options.skills`. For session-level skill behavior, see [Skills](/cli/sdk/skills).
---
## Configuring Subagent mcpServers
`mcpServers` limits or adds MCP servers for a subagent. It is suitable for exposing business tools only to the subagents that need them, such as order lookup, ticket search, or internal knowledge base search.
You can reference an MCP server already configured at the session level:
```typescript TypeScript
const q = query({
prompt: 'Use the support agent to check the latest order status.',
options: {
mcpServers: {
orders: {
type: 'stdio',
command: 'node',
args: ['servers/orders.js'],
},
},
allowedTools: ['Agent'],
agents: {
support: {
description: 'Answers customer support questions using order tools.',
prompt: 'Use order tools when needed and return a concise answer.',
mcpServers: ['orders'],
tools: ['mcp__orders__get_order'],
},
},
},
});
```
```python Python
options = QoderAgentOptions(
mcp_servers={
"orders": {
"command": "python",
"args": ["servers/orders.py"],
},
},
allowed_tools=["Agent"],
agents={
"support": AgentDefinition(
description="Answers customer support questions using order tools.",
prompt="Use order tools when needed and return a concise answer.",
mcpServers=["orders"],
tools=["mcp__orders__lookup_order"],
),
},
)
```
You can also configure a dedicated MCP server for a specific subagent:
```typescript TypeScript
agents: {
knowledge: {
description: 'Searches the internal knowledge base.',
prompt: 'Search the knowledge base and cite the relevant entries.',
mcpServers: [
{
kb: {
type: 'stdio',
command: 'node',
args: ['servers/kb.js'],
},
},
],
tools: ['mcp__kb__search'],
},
}
```
```python Python
options = QoderAgentOptions(
allowed_tools=["Agent"],
agents={
"knowledge": AgentDefinition(
description="Searches the internal knowledge base.",
prompt="Search the knowledge base and cite the relevant entries.",
mcpServers=[
{
"kb": {
"command": "python",
"args": ["servers/kb.py"],
},
},
],
tools=["mcp__kb__search"],
),
},
)
```
Recommendations:
| Scenario | How to configure |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Multiple subagents share one MCP server | Configure the server at session level in the MCP servers option, then reference its name in each subagent's `mcpServers` |
| Only one subagent needs a business tool | Put the server in that subagent's `mcpServers`, and use `tools` to limit callable tools |
| You only want to call a specific MCP tool | Also set `tools: ['mcp__server__tool']` to avoid exposing every tool from the server |
MCP server config structure: see [MCP](/cli/sdk/mcp) and the [Agents Reference](/cli/sdk/references).
---
## Invoking Subagents
Subagents have three common invocation modes.
### Automatic Invocation
The model decides whether to call a subagent based on the task and each subagent's `description`. Clear descriptions improve routing accuracy.
```typescript TypeScript
agents: {
tester: {
description: 'Runs tests and analyzes test failures.',
prompt: 'Run relevant tests and explain any failures clearly.',
tools: ['Bash', 'Read', 'Grep'],
},
}
```
```python Python
agents = {
"tester": AgentDefinition(
description="Runs tests and analyzes test failures.",
prompt="Run relevant tests and explain any failures clearly.",
tools=["Bash", "Read", "Grep"],
),
}
```
### Explicit Invocation
If you want the model to use a specific subagent, name it in the prompt.
```typescript TypeScript
const q = query({
prompt: 'Use the tester agent to run the unit tests and summarize failures.',
options: {
// Pre-authorize Agent tool calls. If options.tools restricts the tool set, include 'Agent' there too.
allowedTools: ['Agent'],
agents: {
tester: {
description: 'Runs tests and analyzes failures.',
prompt: 'Run the requested tests and explain failures clearly.',
tools: ['Bash', 'Read', 'Grep'],
},
},
},
});
```
```python Python
async for message in query(
prompt="Use the tester agent to run the unit tests and summarize failures.",
options=QoderAgentOptions(
allowed_tools=["Agent"],
agents={
"tester": AgentDefinition(
description="Runs tests and analyzes failures.",
prompt="Run the requested tests and explain failures clearly.",
tools=["Bash", "Read", "Grep"],
),
},
),
):
print(message)
```
### Run as the Main Session Role
`options.agent` makes the main session run directly as a subagent identity.
```typescript TypeScript
const q = query({
prompt: 'Plan the refactor for the payment module.',
options: {
agents: {
planner: {
description: 'Plans implementation work before code changes.',
prompt: 'Break the task into clear steps, risks, and validation checks.',
tools: ['Read', 'Grep', 'Glob'],
model: 'inherit',
},
},
agent: 'planner',
},
});
```
```python Python
options = QoderAgentOptions(
agents={
"planner": AgentDefinition(
description="Plans implementation work before code changes.",
prompt="Break the task into clear steps, risks, and validation checks.",
tools=["Read", "Grep", "Glob"],
model="inherit",
),
},
agent="planner",
)
```
`options.agent` can reference a custom subagent in `options.agents`, or a built-in, user, project, or plugin subagent discovered by the current CLI.
---
## Subagent Context and Results
A subagent runs in an independent context. It receives its own system prompt and delegation prompt, but it does not directly inherit the parent session's full history.
| Subagent can see | Subagent cannot see |
| ------------------------------------------------------------------- | ---------------------------------------------------------- |
| Its own `prompt` | Full parent-session conversation history |
| The task prompt passed by the main session through the `Agent` tool | Intermediate tool results from the parent session |
| Its own available tool definitions | Parent session private reasoning that was not passed to it |
| Skills preloaded by configuration | Intermediate context from other Agents |
The main channel for passing information from the parent session to a subagent is the task prompt passed when calling the Agent tool. If a subagent needs specific file paths, error messages, or business context, make the main session pass them explicitly during delegation.
When a subagent completes, the parent session receives its final response, not the full context of every internal tool call. This is one of the main benefits of using subagents to isolate context.
---
## Combined Examples
### Multi-role Collaboration
Register multiple subagents with different roles. The main session decides whether and when to call them based on the task.
```typescript TypeScript
const q = query({
prompt: 'Add input validation to the user registration endpoint.',
options: {
// Pre-authorize Agent tool calls. If options.tools restricts the tool set, include 'Agent' there too.
allowedTools: ['Agent'],
agents: {
researcher: {
description: 'Reads existing code to understand patterns and constraints.',
prompt: 'Research relevant files and report implementation constraints. Do not edit.',
tools: ['Read', 'Grep', 'Glob'],
maxTurns: 8,
},
implementer: {
description: 'Implements code changes following existing project conventions.',
prompt: 'Implement the requested change with minimal, idiomatic edits.',
tools: ['Read', 'Edit', 'Write', 'Grep', 'Glob'],
maxTurns: 12,
},
tester: {
description: 'Runs tests and explains failures.',
prompt: 'Run relevant tests, summarize results, and identify failing cases.',
tools: ['Bash', 'Read', 'Grep'],
maxTurns: 6,
},
},
},
});
```
```python Python
options = QoderAgentOptions(
allowed_tools=["Agent"],
agents={
"researcher": AgentDefinition(
description="Reads existing code to understand patterns and constraints.",
prompt="Research relevant files and report implementation constraints. Do not edit.",
tools=["Read", "Grep", "Glob"],
maxTurns=8,
),
"implementer": AgentDefinition(
description="Implements code changes following existing project conventions.",
prompt="Implement the requested change with minimal, idiomatic edits.",
tools=["Read", "Edit", "Write", "Grep", "Glob"],
maxTurns=12,
),
"tester": AgentDefinition(
description="Runs tests and explains failures.",
prompt="Run relevant tests, summarize results, and identify failing cases.",
tools=["Bash", "Read", "Grep"],
maxTurns=6,
),
},
)
```
### Automatically Run the First Task After Startup
`initialPrompt` only takes effect when that subagent becomes the main session role through `options.agent`:
```typescript TypeScript
const q = query({
prompt: '',
options: {
agents: {
auditor: {
description: 'Audits code for security risks.',
prompt: 'Scan code for security risks and produce a concise report.',
initialPrompt: 'Start with the authentication and session management code.',
tools: ['Read', 'Grep', 'Glob'],
effort: 'high',
},
},
agent: 'auditor',
},
});
```
```python Python
options = QoderAgentOptions(
agents={
"auditor": AgentDefinition(
description="Audits code for security risks.",
prompt="Scan code for security risks and produce a concise report.",
initialPrompt="Start with the authentication and session management code.",
tools=["Read", "Grep", "Glob"],
effort="high",
),
},
agent="auditor",
)
async for message in query(prompt="", options=options):
print(message)
```
If `auditor` is called as a subagent through the main session's `Agent` tool, `initialPrompt` is ignored.
---
## Common Pitfalls
- When directly using a built-in subagent, do not redefine a subagent with the same name in `options.agents` unless you intentionally want to override it.
- Calling subagents relies on the main session's `Agent` tool. `Agent` in the allowlist is the pre-approval; when restricting with `options.tools`, include `Agent` as well.
- Subagent names are case-sensitive and must match the discovered result, such as `Explore` and `Plan` with capitalized first letters.
- `description` tells the model when to call the subagent; `prompt` tells the subagent what to do after it is called.
- Subagents cannot spawn their own subagents. Do not put `Agent` in a subagent's `tools`.
- `initialPrompt` only takes effect for the main session role specified by `options.agent`; it is ignored when the agent is delegated to as a subagent.
- Dedicated MCP servers for subagents can be configured through `mcpServers`; see [MCP](/cli/sdk/mcp) for MCP connection methods.
- In Python, `AgentDefinition` field names are camelCase, not snake\_case.
---
## Continue Reading
- [Agents Reference](/cli/sdk/references): Complete reference for `AgentDefinition`, `AgentInfo`, `options.agent`, and `options.agents`.
- [Tools](/cli/sdk/tools): Built-in tools, custom tools, and tool permissions.
- [Permissions](/cli/sdk/permissions): permission modes, tool allowlists, and permission callbacks.
- [Skills](/cli/sdk/skills): Session-level and subagent-level skill configuration.
# Skills
In this page, the "main session" is the session driven directly by `query()` (or Python's `QoderSDKClient`), as opposed to subagents delegated via the `Agent` tool. See [Subagents](/cli/sdk/agents) for how the two relate.
`options.skills` controls the main session's skill context and the `Skill` tool invocation policy. With a list of strings, the SDK issues the main-session skill allowlist and compiles each entry into `Skill(name)` merged into the tool allowlist (`allowedTools` / `allowed_tools`); with `'all'`, all discovered skills may be invoked and the main-session context is not additionally filtered.
## SDK Does Not Load Built-in Skills
The SDK **always** appends `--disable-builtin-skills` when launching the CLI, so sessions never get the CLI's factory built-in skills (`simplify`, `debug`, `security-review`, `quest`, `batch`, `agent-creator`, `hook-config`, `mcp-config`, `skill-creator`, etc.). The discovery list (TypeScript's `initializationResult().skills`, Python's `get_server_info()['skills']`) contains no `source: 'built-in'` entries either, and the model system prompt can't see them.
This is fixed SDK behavior with no opt-in; if you want the capability of a CLI built-in skill, either ship your own copy of the SKILL.md via a plugin / user dir / project dir, or run the CLI directly outside the SDK.
The session can still pick up skills contributed from these sources:
- **plugin skills**: loaded via `options.plugins`, addressed with the plugin-qualified name (`plugin:skill`).
- **User / project skills**: discovered after explicitly enabling `user` / `project` / `local` via the setting sources option.
- **agent-preloaded skills**: declared on `options.agents[name].skills`, scoped to that sub-agent only.
To know reliably which skills the session discovered, read the discovery list at runtime instead of hard-coding the set.
---
## Using CLI Default Policy
Without `skills`, the SDK injects no extra `Skill` allowlist and defers entirely to CLI policy. Since built-in skills are disabled, sessions without setting sources / plugins have an empty discovery list.
```typescript TypeScript
import { query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Analyze the test coverage of this project',
options: {
cwd: '/path/to/project',
},
});
```
```python Python
from qoder_agent_sdk import query, QoderAgentOptions
async for msg in query(
prompt="Analyze the test coverage of this project",
options=QoderAgentOptions(cwd="/path/to/project"),
):
print(msg)
```
## Enabling All Discovered Skills
```typescript TypeScript
const q = query({
prompt: 'Use an appropriate skill to perform a code review',
options: {
cwd: '/path/to/project',
settingSources: ['project'],
skills: 'all',
},
});
```
```python Python
async for msg in query(
prompt="Use an appropriate skill to perform a code review",
options=QoderAgentOptions(
cwd="/path/to/project",
setting_sources=["project"],
skills="all",
),
):
print(msg)
```
`skills` set to `'all'` lets the `Skill` tool invoke every skill the CLI currently discovers (sources determined by setting sources / plugins; built-ins are no longer included).
## Enabling Only Specific Skills
```typescript TypeScript
const q = query({
prompt: 'Use the review skill to inspect recent changes',
options: {
cwd: '/path/to/project',
settingSources: ['project'],
skills: ['review'],
},
});
```
```python Python
async for msg in query(
prompt="Use the review skill to inspect recent changes",
options=QoderAgentOptions(
cwd="/path/to/project",
setting_sources=["project"],
skills=["review"],
),
):
print(msg)
```
With a string list, only matching skills appear in the main model's skill listing and can be invoked through the `Skill` tool. Entries may be bare or plugin-qualified names. Passing an empty list `[]` hides and rejects every skill in the main session.
The list doesn't change CLI discovery; unlisted skills may still appear in the [discovery list](#reading-skills-discovered-in-the-current-session).
## Enabling Plugin Skills
Plugin skills use the plugin-qualified name `plugin:skill`. For plugin loading methods, see [Plugins documentation](/cli/sdk/plugins).
```typescript TypeScript
const q = query({
prompt: 'Use the echo skill provided by the plugin to handle this input',
options: {
plugins: [{ type: 'local', path: '/path/to/sdk-test-plugin' }],
skills: ['sdk-test-plugin:sdk-echo'],
},
});
```
```python Python
async for msg in query(
prompt="Use the echo skill provided by the plugin to handle this input",
options=QoderAgentOptions(
plugins=[{"type": "local", "path": "/path/to/sdk-test-plugin"}],
skills=["sdk-test-plugin:sdk-echo"],
),
):
print(msg)
```
## Merging with Explicit Tool Allowlist
```typescript TypeScript
const q = query({
prompt: 'Read the source and use the review skill to produce a list of issues',
options: {
cwd: '/path/to/project',
settingSources: ['project'],
allowedTools: ['Read', 'Grep'],
skills: ['review'],
},
});
```
```python Python
async for msg in query(
prompt="Read the source and use the review skill to produce a list of issues",
options=QoderAgentOptions(
cwd="/path/to/project",
setting_sources=["project"],
allowed_tools=["FileRead", "Grep"],
skills=["review"],
),
):
print(msg)
```
The configuration above ultimately allows the listed read/search tools plus `Skill(review)`. The SDK merges and dedupes—no duplicate entries are written.
## Hiding Discovered Skills
The string-list form of `options.skills` filters the main-session model context and restricts `Skill` tool calls, but doesn't change discovery results. To hide a plugin / user / project skill from the discovery list as well, use [settings.skillOverrides](/cli/sdk/references).
```typescript TypeScript
const q = query({
prompt: 'Handle this task',
options: {
plugins: [{ type: 'local', path: '/path/to/sdk-test-plugin' }],
settings: {
skillOverrides: {
'sdk-test-plugin:sdk-echo': 'off',
},
},
},
});
```
```python Python
options = QoderAgentOptions(
plugins=[{"type": "local", "path": "/path/to/sdk-test-plugin"}],
settings={
"skillOverrides": {
"sdk-test-plugin:sdk-echo": "off",
},
},
)
```
- `'off'`: fully hidden—absent from the discovery list and the model system prompt, and `Skill` tool calls are rejected.
- Other values: `'on'` (default), `'name-only'` (only shows name, not description), `'user-invocable-only'` (invisible to model, user can still trigger via `/name`).
- Scope of effect: every SDK-visible source (plugin, user, project, …) respects this override; CLI built-ins are already blocked by `--disable-builtin-skills`, so overrides for them have nothing to act on.
- Key naming rules: Plugin skills use the plugin-qualified name `plugin:skill`; non-plugin skills use bare names. Both forms can be written simultaneously; matching is attempted against the fully qualified name first, then falls back to the bare name.
> `options.skills` can hide the main session's model context but doesn't filter the discovery list; to hide from the discovery list too, use `skillOverrides: { name: 'off' }`.
---
## Reading Skills Discovered in the Current Session
The initialization result contains the full skill list the CLI discovered in this session, unfiltered by the string-list form of `options.skills`. It suits host UIs showing "discovered skills" and is not the main session's current invocable list. In Python, `query()` is a one-shot stream with no convenient query API—use `QoderSDKClient` to read it after the handshake.
```typescript TypeScript
const q = query({
prompt: 'Do not execute any task yet',
options: {
cwd: '/path/to/project',
settingSources: ['project'],
skills: 'all',
},
});
const init = await q.initializationResult();
console.log(init.skills?.map((skill) => skill.name));
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, QoderSDKClient
options = QoderAgentOptions(
cwd="/path/to/project",
setting_sources=["project"],
skills="all",
)
async with QoderSDKClient(options) as client:
info = await client.get_server_info()
if info:
for skill in info.get("skills", []):
print(skill["name"], skill.get("source"))
```
> A string-list `skills` controls main-session context and tool visibility; it is not a security boundary. Unlisted skills do not appear in the model's skill listing and cannot be invoked through the `Skill` tool, but their files remain on disk and can still be accessed by regular file tools.
---
## Custom Agent Preloading Skills
If you define custom sub-Agents via `options.agents`, you can declare `skills` in the Agent definition. When the main session invokes the `Agent` tool, the sub-Agent will run with the specified skills loaded.
```typescript TypeScript
const q = query({
prompt: 'Dispatch a helper agent that uses the sdk-agent-marker skill to return the marker',
options: {
cwd: '/path/to/project',
allowedTools: ['Agent'],
agents: {
'sdk-skill-helper': {
description: 'Invoke when the sdk-agent-marker skill is needed.',
prompt: 'You are a helper agent that only reads and runs the specified skill.',
skills: ['sdk-agent-marker'],
maxTurns: 2,
},
},
},
});
```
```python Python
from qoder_agent_sdk import AgentDefinition, QoderAgentOptions
options = QoderAgentOptions(
cwd="/path/to/project",
allowed_tools=["Agent"],
agents={
"sdk-skill-helper": AgentDefinition(
description="Invoke when the sdk-agent-marker skill is needed.",
prompt="You are a helper agent that only reads and runs the specified skill.",
skills=["sdk-agent-marker"],
maxTurns=2,
),
},
)
```
Such `skills` only affect that agent's context and don't enable the same skills for the main session—the main session's tool allowlist is untouched by this change.
---
## Options Reference
| Field (TypeScript / Python) | Description |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
| `skills` / `skills` | List restricts the main session's skill context and invocation; `[]` disables all; `'all'` enables every discovered skill |
| `agents` / `agents` | Custom agents; an agent definition can declare its own `skills` preload list |
| `allowedTools` / `allowed_tools` | Tool allowlist; merged and deduped with `Skill(...)` entries compiled from `skills` |
| `settingSources` / `setting_sources` | Decides whether the CLI scans user / project directories for skills (default empty = sandboxed) |
| `plugins` / `plugins` | Loads plugins; their skills join the discovery set |
`settings` also has several skill-related fields that the SDK passes through; actual effects depend on whether the CLI version implements them:
| Field | Purpose |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `skillOverrides` | Set `'on' \ | 'name-only' \ | 'user-invocable-only' \ | 'off'` per skill name; plugin, user, project sources all respect this override |
| `skillListingMaxDescChars` | Character limit per description in the skill listing; the SDK passes it through and the default depends on the CLI version |
| `skillListingBudgetFraction` | Context-window fraction reserved for the skill listing; the SDK passes it through and the default depends on the CLI version |
---
## Return Value Reference
```typescript TypeScript
type SDKControlInitializeResponse = {
skills?: Array<{ name: string; description?: string; source?: string }>;
// ...also returns commands / agents / models and similar fields
};
```
```python Python
# The dict returned by client.get_server_info() includes:
{
"commands": [{"name": str, "description": str, ...}, ...],
"agents": [{"name": str, "description": str, "model": str | None}, ...],
"skills": [{"name": str, "description": str | None, "source": str | None}, ...],
# Also includes models / account / output_style and other fields
}
```
Only skill-related fields are shown; full type in [SDK References](/cli/sdk/references). In Python, the streaming `SystemMessage(subtype="init").data["skills"]` is a list of skill names—not the same structure as this metadata-rich discovery list.
---
## Best Practices
- **Enable `skills` deliberately**: `'all'` suits development and debugging; end-user products should usually pass an explicit list.
- **Recreate built-in skill behavior yourself if you want it**: the SDK won't inject `simplify` / `security-review` into sessions; provide your own SKILL.md within plugin or setting-sources scope.
- **Don't treat `skills` as a sandbox**: security boundaries belong to tool allow/deny lists, the permission callback, permission modes, and sandboxing combined.
- **Use the discovery list for UIs**: `initializationResult().skills` / `get_server_info()['skills']` is the stable entry into CLI discovery—use it to show "discovered skills", not as the main session's invocable set.
- **Manage sub-Agent `skills` separately**: They are independent lists from the main session's `options.skills` and do not override each other.
---
## Current Limitations
- `--disable-slash-commands` is the CLI's switch to disable all slash-command skills at once; the SDK currently exposes no first-class option—avoid relying on non-public passthrough paths.
- `settings.skillListingMaxDescChars` and `settings.skillListingBudgetFraction` are listing-budget control fields that the SDK passes through; the current qodercli has not implemented listing budget control, so passing them does not raise an error but also does not change behavior.
- The Python SDK does not yet provide a `client.supported_skills()` convenience method; read from `get_server_info()['skills']` instead (already on the backlog).
# Plugins
`options.plugins` is used to load local plugin directories into the current session. The SDK converts each local plugin into a `--plugin-dir ` startup argument; commands, agents, skills, and MCP servers contained in the plugin all take part in capability discovery for the session.
## Loading Local Plugins
```typescript TypeScript
import { query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'List the commands and agents contributed by the current plugins',
options: {
plugins: [
{ type: 'local', path: '/path/to/my-plugin' },
],
},
});
const init = await q.initializationResult();
console.log(init.commands);
console.log(init.agents);
console.log(init.skills);
const plugins = await q.listPlugins();
console.log(plugins);
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, QoderSDKClient
options = QoderAgentOptions(
plugins=[
{"type": "local", "path": "/path/to/my-plugin"},
],
)
async with QoderSDKClient(options) as client:
info = await client.get_server_info()
print(info.get("commands"))
print(info.get("agents"))
print(info.get("skills"))
plugins = await client.list_plugins()
print(plugins)
```
You can pass multiple local plugins at once; multiple `--plugin-dir` arguments will be written in order:
```typescript TypeScript
const q = query({
options: {
plugins: [
{ type: 'local', path: '/path/to/plugin-a' },
{ type: 'local', path: '/path/to/plugin-b' },
],
},
});
```
```python Python
options = QoderAgentOptions(
plugins=[
{"type": "local", "path": "/path/to/plugin-a"},
{"type": "local", "path": "/path/to/plugin-b"},
],
)
```
> 💡 In Python, `query()` is a one-shot message stream and can't query the init response after the handshake. To read plugin-contributed commands / agents / skills, use `QoderSDKClient` and call `get_server_info()` after `connect()`, or capture `SystemMessage(subtype='init')` in the stream and read `message.data` yourself. For the full plugin inventory, call `client.list_plugins()`.
---
## Plugin Directory Layout
A local plugin typically contains:
```
my-plugin/
.qoder-plugin/plugin.json
commands/
agents/
skills/
.mcp.json
```
`.qoder-plugin/plugin.json` declares the plugin name, version, and description. The other directories are automatically scanned by the CLI based on file type.
The SDK does not validate whether the path exists or is well-formed:
- A non-existent `--plugin-dir` path is silently ignored in SDK mode; the session still initializes normally.
- Broken frontmatter or `.mcp.json` does not block init; broken commands simply do not appear in the init response.
- To diagnose plugin load failures explicitly, the only fallback today is the [post-reload error\_count](#reloading-plugins-at-runtime).
---
## Plugin-contributed Slash Commands
`commands/*.md` in a plugin appears in the initialization result, named in the `:` qualified form:
```typescript TypeScript
const commands = await q.supportedCommands();
console.log(commands.map((cmd) => cmd.name));
```
```python Python
async with QoderSDKClient(options) as client:
info = await client.get_server_info()
for cmd in info.get("commands", []):
print(cmd["name"], cmd.get("description"))
```
## Plugin-contributed Agents
`agents/*.md` in a plugin appears in the initialization result; the SDK offers a convenience method to fetch the list:
```typescript TypeScript
const agents = await q.supportedAgents();
console.log(agents.map((agent) => agent.name));
```
```python Python
async with QoderSDKClient(options) as client:
for agent in client.supported_agents():
print(agent["name"], agent.get("description"))
```
## Plugin-contributed Skills
`skills//SKILL.md` in a plugin is registered under the plugin-qualified name (`plugin:skill`). Control its main-session context visibility and invocation policy via `options.skills`: pass qualified names to enable specific skills, `'all'` to enable all discovered ones, or omit for CLI default policy. See the [Skills docs](/cli/sdk/skills#enabling-plugin-skills).
## Plugin-contributed MCP Servers
`.mcp.json` in a plugin is launched by the CLI and included in MCP status:
```typescript TypeScript
const servers = await q.mcpServerStatus();
console.log(servers);
```
```python Python
async with QoderSDKClient(options) as client:
status = await client.get_mcp_status()
for server in status["mcpServers"]:
print(server["name"], server["status"])
```
---
## Temporarily Overriding an Installed Plugin with the Same Name
Plugins loaded via `options.plugins` are session-scoped. During the current session, if a local plugin shares a name with an installed plugin, the local plugin takes priority in capability discovery. This is useful for plugin development, debugging, and canary testing.
```typescript TypeScript
const q = query({
options: {
// The local version only takes effect for this query session and does not
// touch the user's global install state.
plugins: [{ type: 'local', path: './my-plugin-dev' }],
},
});
```
```python Python
options = QoderAgentOptions(
# The local version only takes effect for this query session and does not
# touch the user's global install state.
plugins=[{"type": "local", "path": "./my-plugin-dev"}],
)
```
---
## Reloading Plugins at Runtime
When the plugin directory changes, call `reloadPlugins()` / `reload_plugins()` within the same session to have the CLI rescan plugin resources.
```typescript TypeScript
const refreshed = await q.reloadPlugins();
console.log(refreshed.commands);
console.log(refreshed.agents);
console.log(refreshed.plugins);
console.log(refreshed.mcpServers);
console.log(refreshed.error_count);
```
```python Python
async with QoderSDKClient(options) as client:
refreshed = await client.reload_plugins()
print(refreshed["commands"])
print(refreshed["agents"])
print(refreshed["plugins"])
print(refreshed["mcpServers"])
print(refreshed["error_count"])
```
Typical use cases:
- Refreshing after adding or deleting `commands/*.md` during plugin development.
- After installing or updating a local plugin without restarting the host application.
- When the host UI needs to display commands, agents, plugins, and MCP status after a reload.
> Note: in Python, `reload_plugins()` is only meaningful in `QoderSDKClient` (streaming) mode; the one-shot `query()` stream has no runtime control channel.
---
## Options Reference
| Field (TypeScript / Python) | Description |
| ------------------------------------ | --------------------------------------------------------------------------------------- |
| `plugins` / `plugins` | Loads local plugin directories; `{ type: 'local', path }` is the common form |
| `settings` / `settings` | Settings passed through to the CLI; may include `enabledPlugins`, `pluginConfigs`, etc. |
| `settingSources` / `setting_sources` | Controls which settings sources the CLI reads |
Use `settings.enabledPlugins` to control plugin enablement and `settings.pluginConfigs` to supply plugin config such as MCP server replacements.
---
## Return Value Reference
### Initialization result
`initializationResult()` (TypeScript) / `client.get_server_info()` (Python) returns the commands, agents, skills, and other initialization resources discovered in the session. It has no stable plugin-inventory field; full return type in [SDK References](/cli/sdk/references).
```python
{
"commands": [
{"name": "plugin-a:greet", "description": "...", "argumentHint": "..."},
...
],
"agents": [
{"name": "plugin-a:helper", "description": "...", "model": "sonnet"},
...
],
"skills": [
{"name": "plugin-a:echo", "description": "...", "source": "plugin"},
...
],
# Also includes models / account / output_style and other fields
}
```
### Listing plugins
```typescript TypeScript
listPlugins(): Promise;
```
```python Python
plugins = await client.list_plugins()
```
Reads the CLI's plugin inventory with a resource summary per plugin. Host UIs showing the plugin inventory should use this method rather than the `plugins` field of the initialization result.
Each item is a `PluginDetails` object with `id`, `name`, `source`, `path`, `version`, `scope`, `enabled`, `canDisable`, and a `resources` summary grouped into `skills`, `agents`, `mcpServers`, `commands`, and `hooks`.
### Reloading plugins
`reloadPlugins()` / `reload_plugins()` returns:
```typescript
type SDKControlReloadPluginsResponse = {
commands: Array<{ name: string; description?: string; argumentHint?: string }>;
agents: Array<{ name: string; description?: string }>;
plugins: Array<{ name: string; path: string; source?: string }>;
mcpServers: Array>;
error_count: number; // Number of plugins that failed to load in this reload
};
```
---
## Best Practices
- **Separate initialization resources from the plugin inventory**: show discovered commands/agents/skills from the initialization result; show the plugin inventory via `listPlugins()` / `list_plugins()`. The skills there are a discovery list, not the main session's invocable set.
- **Use `options.plugins` during plugin development**: It only affects the current session without modifying the user's global install state.
- **Prepare user messaging before reloads**: a reload rescans the disk and may briefly change the available resource lists—keep the UI in sync.
- **Check `error_count` for diagnostics**: If `error_count > 0` after reload, some plugin resources failed to load; display the source to the user.
---
## Current Limitations
- On some qodercli versions, a local plugin's commands, agents, and MCP appear in the initialization result while its skills may be missing from the discovery list—a CLI-side discovery issue.
- In the current qodercli implementation, nonexistent `--plugin-dir` paths are silently ignored in SDK mode; the only explicit diagnostic today is the post-reload `error_count`.
- Reload is a runtime control API exposed by the SDK; if your CLI version returns internal `this._plugins` errors, upgrade to a fixed qodercli.
# Permission Control
The Qoder Agent SDK's permission control capabilities manage what the model can do within a single `query()` session. It can restrict which tools are visible to the model, set default authorization policies, delegate tool execution approval to the host application, and apply new rules to the current session after user authorization.
Permission control isn't a single API but a set of options. Typically you decide which tools the session may use, then when those tools may execute, then wire in runtime approval, dynamic rule updates, settings, or hooks as needed.
```typescript TypeScript
const messages = query({
prompt: 'Inspect the repository and summarize risky changes.',
options: {
auth: accessTokenFromEnv(),
cwd: '/path/to/project',
tools: ['Read', 'Grep', 'Bash'],
allowedTools: ['Read', 'Grep'],
disallowedTools: ['Bash'],
permissionMode: 'default',
},
});
for await (const message of messages) {
console.log(message);
}
```
```python Python
from qoder_agent_sdk import QoderAgentOptions, query
async for message in query(
prompt="Inspect the repository and summarize risky changes.",
options=QoderAgentOptions(
cwd="/path/to/project",
tools=["Read", "Grep", "Bash"],
allowed_tools=["Read", "Grep"],
disallowed_tools=["Bash"],
permission_mode="default",
),
):
print(message)
```
The example expresses a common policy: the model sees `Read`, `Grep`, and `Bash`; `Read` and `Grep` are pre-approved; `Bash` is denied. In real projects, add the permission callback (`canUseTool` / `can_use_tool`) to route non-pre-approved operations to your product UI, approval system, or risk service.
## Capability overview
Permission-related options fall into four groups. The first sets the default policy—plan mode, auto-accept edits, no interactive prompts. The second sets tool scope and rules. The third brings the host into runtime approval. The fourth covers advanced settings, hooks, and MCP tool policy.
| Problem to solve | Recommended entry (TypeScript / Python) | Notes |
| --------------------------------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------- |
| Set the session's default permission behavior | `permissionMode` / `permission_mode` | Decides how tool calls are handled when no explicit rule matches |
| Explicitly confirm skipping permission checks | `allowDangerouslySkipPermissions` / `allow_dangerously_skip_permissions` | Only with `bypassPermissions` or `yolo` |
| Restrict tools visible in this session | `tools` | Tools not included are not provided to the model |
| Pre-approve certain tools | `allowedTools` / `allowed_tools` | Matches usually skip the authorization prompt |
| Deny certain tools | `disallowedTools` / `disallowed_tools` | Matches are rejected; takes precedence over allow |
| Let the host approve tool calls | `canUseTool` / `can_use_tool` | The SDK host returns allow or deny at runtime |
| Hand approval to an external prompt tool | `permissionPromptToolName` / `permission_prompt_tool_name` | For runtimes that already provide a permission prompt tool |
| Update session rules after approval | `PermissionUpdate` | Commonly "allow once" or "always allow this session" |
| Allow access outside cwd | `additionalDirectories` / `add_dirs` | Extends the session's accessible directories |
| Provide permission rules from settings | `settings` | Suitable for static permission configuration at session start |
| Intercept or audit during the lifecycle | `hooks` | Suitable for advanced interception, auditing, and alerting |
| Declare tool policy on an MCP server | MCP tool policy | Declare per-tool allow/ask/deny in the MCP server config |
To stay focused on permission config, later examples omit the message-consumption code; real usage still consumes the returned async message stream.
## Quick Start: Host Application Approving Tool Calls
Use the permission callback when tool calls must go through your own approval logic. At runtime the SDK hands your callback the tool name, tool input, and a set of displayable approval details. Returning allow lets the tool run; deny rejects it.
```typescript TypeScript
const readOrder = tool(
'read_order',
'Read an order by ID.',
{ orderId: z.string() },
async ({ orderId }) => ({
content: [{ type: 'text', text: `order:${orderId}` }],
}),
);
const server = createSdkMcpServer({
name: 'orders',
tools: [readOrder],
});
query({
prompt: 'Read order 1001.',
options: {
auth: accessTokenFromEnv(),
mcpServers: { orders: server },
permissionMode: 'default',
async canUseTool(toolName, input, options) {
if (toolName !== 'mcp__orders__read_order') {
return {
behavior: 'deny',
message: 'Only order reads are allowed in this workflow.',
toolUseID: options.toolUseID,
};
}
return {
behavior: 'allow',
updatedInput: input,
toolUseID: options.toolUseID,
};
},
},
});
```
```python Python
from typing import Any
from qoder_agent_sdk import create_sdk_mcp_server, query, tool
from qoder_agent_sdk.types import (
PermissionResultAllow,
PermissionResultDeny,
QoderAgentOptions,
ToolPermissionContext,
)
@tool("read_order", "Read an order by ID.", {"order_id": str})
async def read_order(args: dict[str, Any]) -> dict[str, Any]:
return {"content": [{"type": "text", "text": f"order:{args['order_id']}"}]}
server = create_sdk_mcp_server(name="orders", tools=[read_order])
async def can_use_tool(
tool_name: str,
input_data: dict[str, Any],
context: ToolPermissionContext,
):
if tool_name != "mcp__orders__read_order":
return PermissionResultDeny(
message="Only order reads are allowed in this workflow."
)
return PermissionResultAllow(updated_input=input_data)
async for _ in query(
prompt="Read order 1001.",
options=QoderAgentOptions(
mcp_servers={"orders": server},
permission_mode="default",
can_use_tool=can_use_tool,
),
):
pass
```
Here `read_order` is an SDK MCP tool. When the model calls it, the full tool name is `mcp__orders__read_order`. The permission callback only allows this tool and returns the original input as the updated input. In TypeScript, returning `toolUseID` lets the runtime match the approval result to this exact tool call.
## Controlling Default Policy: permissionMode
The permission mode (`permissionMode` / `permission_mode`) sets the session's default permission policy. It expresses "what mode this session is in overall"—plan first, auto-accept edits, reject without asking, or skip checks in controlled environments.
```typescript TypeScript
query({
prompt: 'Plan the migration. Do not edit files yet.',
options: {
auth: accessTokenFromEnv(),
cwd: '/path/to/project',
permissionMode: 'plan',
},
});
```
```python Python
QoderAgentOptions(
cwd="/path/to/project",
permission_mode="plan",
)
```
`plan` mode is designed for having the model produce a plan before making changes.
| Mode | Behavior |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `default` | Standard permission behavior. Tool calls are processed according to tools, allow/deny rules, dynamic approval, or runtime policy |
| `acceptEdits` | Auto-accepts file edit operations; use this when workspace modification is confirmed |
| `bypassPermissions` | Skips permission checks; requires the explicit skip confirmation as well |
| `yolo` | Compatibility alias of `bypassPermissions`; also requires explicit confirmation |
| `plan` | Plan mode; designed for producing an execution plan first; no actual changes by default |
| `dontAsk` | No interactive prompts. Operations not pre-authorized or allowed by rules are denied |
| `auto` | Runtime capability automatically determines allow or deny. Safe in-workspace file edits may be auto-approved |
To switch modes within a session, use the runtime control method:
```typescript TypeScript
const q = query({
prompt: 'Plan the change first.',
options: {
auth: accessTokenFromEnv(),
cwd: '/path/to/project',
permissionMode: 'plan',
},
});
await q.setPermissionMode('default');
```
```python Python
from qoder_agent_sdk import QoderSDKClient
async with QoderSDKClient(
options=QoderAgentOptions(
cwd="/path/to/project",
permission_mode="plan",
)
) as client:
await client.set_permission_mode("default")
```
`bypassPermissions` and `yolo` are high-risk modes. The SDK requires an explicit `allowDangerouslySkipPermissions: true` (Python: `allow_dangerously_skip_permissions=True`) so ordinary sessions can't accidentally skip permission checks.
```typescript TypeScript
query({
prompt: 'Run the trusted local maintenance task.',
options: {
auth: accessTokenFromEnv(),
cwd: '/path/to/project',
permissionMode: 'bypassPermissions',
allowDangerouslySkipPermissions: true,
},
});
```
```python Python
QoderAgentOptions(
cwd="/path/to/project",
permission_mode="bypassPermissions",
allow_dangerously_skip_permissions=True,
)
```
## Controlling Tool Scope: tools, allowedTools, disallowedTools
Tool control answers "which tools the model can see, and which are allowed or denied by default". The three fields often appear together but differ semantically.
```typescript TypeScript
query({
prompt: 'Inspect the repo without modifying it.',
options: {
auth: accessTokenFromEnv(),
cwd: '/path/to/project',
tools: ['Read', 'Grep', 'Bash'],
allowedTools: ['Read', 'Grep'],
disallowedTools: ['Bash'],
},
});
```
```python Python
QoderAgentOptions(
cwd="/path/to/project",
tools=["Read", "Grep", "Bash"],
allowed_tools=["Read", "Grep"],
disallowed_tools=["Bash"],
)
```
This configuration means: only provide `Read`, `Grep`, and `Bash` tools for this session; `Read` and `Grep` are pre-authorized; `Bash` is denied — even if the model wants to call it, it won't execute.
| Field (TypeScript / Python) | Effect | Best for |
| -------------------------------------- | ------------------------------------------ | --------------------------------------------- |
| `tools` / `tools` | Restricts the session's available tool set | Narrowing the model's capability surface |
| `allowedTools` / `allowed_tools` | Adds allow rules | Letting low-risk tools skip repeated approval |
| `disallowedTools` / `disallowed_tools` | Adds deny rules | Explicitly banning high-risk tools |
When the same tool matches both allow and deny, deny takes priority. This ensures deny rules cannot be bypassed by broader allow rules.
MCP tools also use full tool name matching. For example, with SDK MCP server named `orders` and tool named `read_order`, the full tool name is `mcp__orders__read_order`.
```typescript TypeScript
query({
prompt: 'Read order 1001.',
options: {
auth: accessTokenFromEnv(),
mcpServers: { orders: server },
allowedTools: ['mcp__orders__read_order'],
},
});
```
```python Python
QoderAgentOptions(
mcp_servers={"orders": server},
allowed_tools=["mcp__orders__read_order"],
)
```
## Runtime Approval: canUseTool
Use the permission callback to show “allow once,” “always allow for this session,” or “deny” in your application. The callback can also ask an enterprise risk service whether a command may run. For callback timing, permission-mode effects, and `AskUserQuestion`, see [Approval and User Input](/cli/sdk/user-input).
```typescript TypeScript
query({
prompt: 'Create a changelog file for this release.',
options: {
auth: accessTokenFromEnv(),
cwd: '/path/to/project',
permissionMode: 'default',
async canUseTool(toolName, input, options) {
showApprovalDialog({
title: options.title ?? toolName,
description: options.description,
input,
});
const approved = await waitForUserApproval(options.signal);
if (!approved) {
return {
behavior: 'deny',
message: 'Rejected by user.',
toolUseID: options.toolUseID,
};
}
return {
behavior: 'allow',
updatedInput: input,
toolUseID: options.toolUseID,
};
},
},
});
```
```python Python
async def can_use_tool(
tool_name: str,
input_data: dict[str, Any],
context: ToolPermissionContext,
):
show_approval_dialog(
title=context.title or tool_name,
description=context.description,
input_data=input_data,
)
approved = await wait_for_user_approval(context.signal)
if not approved:
return PermissionResultDeny(message="Rejected by user.")
return PermissionResultAllow(updated_input=input_data)
QoderAgentOptions(
cwd="/path/to/project",
permission_mode="default",
can_use_tool=can_use_tool,
)
```
The callback signature:
```typescript TypeScript
type CanUseTool = (
toolName: string,
input: Record,
options: {
signal: AbortSignal;
suggestions?: PermissionUpdate[];
blockedPath?: string;
decisionReason?: string;
title?: string;
displayName?: string;
description?: string;
toolUseID: string;
agentID?: string;
},
) => Promise;
```
```python Python
CanUseTool = Callable[
[str, dict[str, Any], ToolPermissionContext],
Awaitable[PermissionResult],
]
```
Key fields (on the third `options` parameter in TypeScript, on `context` in Python):
| Field | Description |
| --------------------------------------- | ------------------------------------------------------------------------------------------ |
| Tool name | Full tool name, e.g. `Read`, `Bash`, `mcp__orders__read_order` |
| Input | The tool call's original arguments |
| `toolUseID` / `tool_use_id` | This tool call's ID; in TypeScript, include it in the returned result |
| `signal` | Fires when the authorization request is cancelled; UIs or remote approvals should watch it |
| `title` / `displayName` / `description` | Runtime-generated human-readable text, ready for approval UIs |
| `suggestions` | Runtime-suggested permission updates, usable for "always allow this session" |
| `blockedPath` / `blocked_path` | The restricted path in path-related authorization scenarios |
| `decisionReason` / `decision_reason` | Runtime-provided reasoning, for display or audit |
| `agentID` / `agent_id` | The agent ID when a subagent initiated the tool call |
Return allow to continue executing the tool:
```typescript TypeScript
return {
behavior: 'allow',
updatedInput: input,
toolUseID: options.toolUseID,
};
```
```python Python
return PermissionResultAllow(updated_input=input_data)
```
The updated input is what the tool ultimately receives. Return it unchanged, or modify it post-approval—adding a tenant ID, rewriting paths into a safe directory, or stripping disallowed fields.
Return deny to reject the tool:
```typescript TypeScript
return {
behavior: 'deny',
message: 'This command is not allowed in the current workspace.',
toolUseID: options.toolUseID,
};
```
```python Python
return PermissionResultDeny(
message="This command is not allowed in the current workspace."
)
```
`deny.message` is required; it becomes part of the rejection reason for the model, logs, or host display. If the SDK receives a CLI authorization request without a configured permission callback, it returns an error—nothing is allowed by default.
When the permission system directly denies a tool call, a structured permission denial message may appear in the message stream:
```typescript TypeScript
type SDKPermissionDeniedMessage = {
type: 'system';
subtype: 'permission_denied';
tool_name: string;
tool_use_id?: string;
message?: string;
decision_reason?: string;
decision_reason_type?: string;
};
```
```python Python
from qoder_agent_sdk import SDKPermissionDeniedMessage
if isinstance(message, SDKPermissionDeniedMessage):
print(
message.tool_name,
message.tool_use_id,
message.message,
message.decision_reason,
message.decision_reason_type,
)
```
Such messages typically appear with `dontAsk` mode, auto-rejects, or rule rejects. Hosts can use them to update UI state or write audit logs.
## Updating Permissions Within a Session: PermissionUpdate
`PermissionUpdate` updates the session's permission rules after an approval. The most common case is the user choosing "always allow this session" in the approval UI. Return the runtime's `suggestions` as-is, or construct explicit rules yourself.
```typescript TypeScript
async function canUseTool(toolName, input, options) {
const decision = await showApprovalDialog({
toolName,
suggestions: options.suggestions,
});
if (decision === 'always-allow-this-session') {
return {
behavior: 'allow',
updatedInput: input,
toolUseID: options.toolUseID,
updatedPermissions: options.suggestions,
};
}
if (decision === 'allow-once') {
return {
behavior: 'allow',
updatedInput: input,
toolUseID: options.toolUseID,
};
}
return {
behavior: 'deny',
message: 'Rejected by user.',
toolUseID: options.toolUseID,
};
}
```
```python Python
async def can_use_tool(
tool_name: str,
input_data: dict[str, Any],
context: ToolPermissionContext,
):
decision = await show_approval_dialog(
tool_name=tool_name,
suggestions=context.suggestions,
)
if decision == "always-allow-this-session":
return PermissionResultAllow(
updated_input=input_data,
updated_permissions=context.suggestions,
)
if decision == "allow-once":
return PermissionResultAllow(updated_input=input_data)
return PermissionResultDeny(message="Rejected by user.")
```
You can also construct rules directly:
```typescript TypeScript
return {
behavior: 'allow',
updatedInput: input,
toolUseID: options.toolUseID,
updatedPermissions: [
{
type: 'addRules',
behavior: 'allow',
destination: 'session',
rules: [{ toolName: 'mcp__orders__read_order' }],
},
],
};
```
```python Python
from qoder_agent_sdk.types import PermissionRuleValue, PermissionUpdate
return PermissionResultAllow(
updated_input=input_data,
updated_permissions=[
PermissionUpdate(
type="addRules",
behavior="allow",
destination="session",
rules=[PermissionRuleValue(tool_name="mcp__orders__read_order")],
)
],
)
```
Supported update types:
| Type | Purpose |
| ------------------- | --------------------------------- |
| `addRules` | Append allow, ask, or deny rules |
| `replaceRules` | Replace rules |
| `removeRules` | Remove rules |
| `setMode` | Switch permission mode |
| `addDirectories` | Append allowed access directories |
| `removeDirectories` | Remove directory authorizations |
Prefer writing dynamic permission updates to the current session (`destination: 'session'`). `session` only affects subsequent checks in this query session. For persistence at local/project/user level, prefer a settings-management flow over dynamic updates from a single approval callback.
## Additional directories
By default the session treats `cwd` as the primary working directory. When the model must read or modify directories outside `cwd`, pass them explicitly (TypeScript: `additionalDirectories`; Python: `add_dirs`).
```typescript TypeScript
query({
prompt: 'Inspect the app and the shared package.',
options: {
auth: accessTokenFromEnv(),
cwd: '/repo/app',
additionalDirectories: ['/repo/packages/shared'],
},
});
```
```python Python
QoderAgentOptions(
cwd="/repo/app",
add_dirs=["/repo/packages/shared"],
)
```
This configuration means the session's main working directory is `/repo/app`, and the model is also allowed to access `/repo/packages/shared`. This works well for monorepos, cross-repository debugging, shared library investigation, and similar scenarios.
During execution, directory authorization can also be adjusted via `PermissionUpdate`:
```typescript TypeScript
return {
behavior: 'allow',
updatedInput: input,
toolUseID: options.toolUseID,
updatedPermissions: [
{
type: 'addDirectories',
destination: 'session',
directories: ['/repo/packages/shared'],
},
],
};
```
```python Python
return PermissionResultAllow(
updated_input=input_data,
updated_permissions=[
PermissionUpdate(
type="addDirectories",
destination="session",
directories=["/repo/packages/shared"],
)
],
)
```
Directory authorization is part of the permission boundary. Don't make broad directories a default; add the minimal set per task instead.
## External Authorization Tool: permissionPromptToolName
This option (TypeScript: `permissionPromptToolName`; Python: `permission_prompt_tool_name`) hands permission requests to a permission prompt tool in the runtime environment instead of implementing the permission callback in the SDK host. It suits existing external approval tools, remote runtimes, or unified permission gateways.
```typescript TypeScript
query({
prompt: 'Run the task.',
options: {
auth: accessTokenFromEnv(),
permissionPromptToolName: 'mcp__permission_server__approve',
},
});
```
```python Python
QoderAgentOptions(
permission_prompt_tool_name="mcp__permission_server__approve",
)
```
Three things to note:
- It must be a prompt tool name the current runtime recognizes.
- It is mutually exclusive with the permission callback (`canUseTool` / `can_use_tool`).
- When the SDK host itself decides approvals, prefer the permission callback.
The permission prompt tool receives the following input:
```typescript
type PermissionPromptToolInput = {
tool_name: string;
input: Record;
tool_use_id?: string;
};
```
It needs to return a permission result:
```typescript
type PermissionPromptToolOutput =
| {
behavior: 'allow';
updatedInput: Record;
updatedPermissions?: PermissionUpdate[];
toolUseID?: string;
}
| {
behavior: 'deny';
message: string;
interrupt?: boolean;
toolUseID?: string;
};
```
`allow.updatedInput` is the final parameters used when executing the tool. If you want to keep the original parameters, return the received `input` as-is. `deny.message` is required. `interrupt: true` means deny and also interrupt the current Agent flow.
## Using settings to Provide Permission Rules
`settings` provides static permission configuration before the session starts. It beats the permission callback at expressing "what this project allows, denies, and which extra directories exist".
```typescript TypeScript
query({
prompt: 'Inspect the project.',
options: {
auth: accessTokenFromEnv(),
cwd: '/path/to/project',
settings: {
permissions: {
allow: ['Read', 'Grep'],
deny: ['Bash'],
ask: ['Write'],
defaultMode: 'default',
additionalDirectories: ['/path/to/shared-lib'],
},
},
},
});
```
```python Python
QoderAgentOptions(
cwd="/path/to/project",
settings={
"permissions": {
"allow": ["Read", "Grep"],
"deny": ["Bash"],
"ask": ["Write"],
"defaultMode": "default",
"additionalDirectories": ["/path/to/shared-lib"],
}
},
)
```
Field descriptions:
| Field | Description |
| ------------------------------------------ | ----------------------------------------------------- |
| `permissions.allow` | Allow rules |
| `permissions.deny` | Deny rules |
| `permissions.ask` | Always-ask rules |
| `permissions.defaultMode` | Default permission mode |
| `permissions.disableBypassPermissionsMode` | Set to `'disable'` to disable bypass permissions mode |
| `permissions.additionalDirectories` | Additional accessible directories |
If your application reads and applies the default permission mode from settings, consider performing your own product-level confirmation before executing high-risk modes. Modes like `bypassPermissions` and `yolo` should only appear in explicitly trusted environments.
## Using hooks for Advanced Interception and Auditing
Hooks suit teams already on the SDK hooks system that want finer-grained control across the tool lifecycle. Compared with the permission callback, hooks fit cross-cutting logic: auditing, alerting, unified interception, recording rejection reasons.
```typescript TypeScript
query({
prompt: 'Inspect the repo.',
options: {
auth: accessTokenFromEnv(),
cwd: '/path/to/project',
hooks: {
PreToolUse: [
{
matcher: 'Bash',
hooks: [
async (input) => {
return {
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'deny',
permissionDecisionReason: 'Shell commands are disabled here.',
},
};
},
],
},
],
},
},
});
```
```python Python
from qoder_agent_sdk import HookMatcher
async def pre_tool_use_hook(inp, tool_use_id, context):
return {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Shell commands are disabled here.",
}
}
QoderAgentOptions(
cwd="/path/to/project",
hooks={
"PreToolUse": [
HookMatcher(matcher="Bash", hooks=[pre_tool_use_hook]),
],
},
)
```
The main permission-related hooks are three types:
| Hook | Trigger Timing | Common Use |
| ------------------- | ---------------------------------- | -------------------------------------------------------- |
| `PreToolUse` | Before tool invocation | Pre-allow, deny, request ask, or pass to subsequent flow |
| `PermissionRequest` | When entering a permission request | Return allow or deny directly before the normal prompt |
| `PermissionDenied` | After permission is denied | Auditing, alerting, recording denial reasons |
`PreToolUse` can return:
```typescript
{
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'allow' | 'deny' | 'ask' | 'defer',
permissionDecisionReason?: string,
updatedInput?: Record,
},
}
```
`PermissionRequest` can return a permission result similar to tool approval:
```typescript
{
hookSpecificOutput: {
hookEventName: 'PermissionRequest',
decision: {
behavior: 'deny',
message: 'Denied by policy.',
},
},
}
```
`PermissionDenied` is typically used for observing results, not for allowing tools. Its input includes the denied tool name, tool input, tool invocation ID, and denial reason.
## MCP Tool Policy
If a permission policy naturally belongs to one MCP server, declare tool-level permission policy right in the MCP server config. The policy travels with the server config instead of being scattered across global tool allow/deny lists.
```typescript TypeScript
query({
prompt: 'Use repo tools.',
options: {
auth: accessTokenFromEnv(),
mcpServers: {
repo_tools: {
type: 'http',
url: process.env.REPO_TOOLS_MCP_URL!,
tools: [
{ name: 'search', permission_policy: 'always_allow' },
{ name: 'write_file', permission_policy: 'always_ask' },
{ name: 'delete_file', permission_policy: 'always_deny' },
],
},
},
},
});
```
```python Python
import os
QoderAgentOptions(
mcp_servers={
"repo_tools": {
"type": "http",
"url": os.environ["REPO_TOOLS_MCP_URL"],
"tools": [
{"name": "search", "permission_policy": "always_allow"},
{"name": "write_file", "permission_policy": "always_ask"},
{"name": "delete_file", "permission_policy": "always_deny"},
],
}
},
)
```
Policy meanings:
| Policy | Behavior |
| -------------- | -------------------------------------- |
| `always_allow` | Matched tool is directly allowed |
| `always_ask` | Matched tool enters authorization flow |
| `always_deny` | Matched tool is directly denied |
`name` can be the MCP tool's original name or the full tool name, e.g., `mcp__repo_tools__search`. During actual matching, the runtime maps policy names to the current MCP tool invocation.
# Hooks
Hooks allow you to inject custom logic at key lifecycle points of an AI session, enabling audit logging, security controls, context injection, and dynamic behavior modification.
## Event Overview
| Event | Trigger | Controllable Behavior |
| -------------------- | ----------------------------- | ---------------------------------------- |
| `PreToolUse` | Before tool invocation | Intercept / allow / modify input |
| `PostToolUse` | After tool succeeds | Audit / inject context / override output |
| `PostToolUseFailure` | After tool fails | Error handling / logging |
| `UserPromptSubmit` | Before user prompt is sent | Inject context / intercept |
| `SessionStart` | Session begins | Initialize / inject context |
| `SessionEnd` | Session ends | Cleanup / logging |
| `Stop` | AI stops generating | Prevent stop, force continuation |
| `SubagentStart` | Subagent starts | Observe / log |
| `SubagentStop` | Subagent stops | Observe / log |
| `PreCompact` | Before context compaction | Observe / log |
| `PostCompact` | After context compaction | Observe / log |
| `CwdChanged` | Working directory changes | Observe / log |
| `InstructionsLoaded` | Instruction file loaded | Observe / log |
| `FileChanged` | File created/modified/deleted | Observe / log |
| `PermissionRequest` | Permission requested | Auto-approve / deny permission requests |
See [SDK References](/cli/sdk/references) for the full event type definitions.
## Configuration
Configure hooks in the `hooks` field of options:
```typescript TypeScript
import { query } from '@qoder-ai/qoder-agent-sdk';
import type { HookCallback, HookCallbackMatcher } from '@qoder-ai/qoder-agent-sdk';
const result = query({
prompt: 'perform task',
options: {
hooks: {
PreToolUse: [{ matcher: 'Bash', hooks: [myHook] }],
PostToolUse: [{ hooks: [auditHook] }],
SessionEnd: [{ hooks: [logHook] }],
},
},
});
for await (const message of result) {
// process messages
}
```
```python Python
from qoder_agent_sdk import query, QoderAgentOptions, HookMatcher
async for msg in query(
prompt="perform task",
options=QoderAgentOptions(
hooks={
"PreToolUse": [HookMatcher(matcher="Bash", hooks=[my_hook])],
"PostToolUse": [HookMatcher(hooks=[audit_hook])],
"SessionEnd": [HookMatcher(hooks=[log_hook])],
},
),
):
... # process messages
```
### Matcher
The `matcher` field is a regex pattern — hooks only fire when the tool name matches:
```typescript TypeScript
const result = query({
prompt: 'perform task',
options: {
hooks: {
PreToolUse: [
{ matcher: 'Bash', hooks: [bashAuditHook] }, // Bash only
{ matcher: 'File.*|Write|Edit', hooks: [fileAuditHook] }, // File operations
{ hooks: [generalLogHook] }, // All tools (no matcher)
],
},
},
});
```
```python Python
hooks={
"PreToolUse": [
HookMatcher(matcher="Bash", hooks=[bash_audit]), # Bash only
HookMatcher(matcher="File.*|Write|Edit", hooks=[file_audit]), # File operations
HookMatcher(hooks=[general_log]), # All tools (no matcher)
],
}
```
### Callback Functions
Each hook callback receives the event input, the tool-use ID, and a context (an abort signal in TypeScript):
```typescript TypeScript
type HookCallback = (
input: HookInput,
toolUseID: string | undefined,
options: { signal: AbortSignal },
) => Promise;
```
```python Python
HookCallback = Callable[
[HookInput, str | None, HookContext],
Awaitable[HookJSONOutput],
]
```
#### Inputs
All events share common fields: `hook_event_name` (event type), `session_id` (session ID), `transcript_path` (transcript file path), `cwd` (working directory). Each event also has event-specific fields, such as `tool_name` and `tool_input` for `PreToolUse`.
See [SDK References](/cli/sdk/references) for full input type definitions.
#### Outputs
The callback returns an object / dict that controls behavior via:
- `continue: false` — ends the session (Python field name `continue_`, serialized to JSON `"continue"`)
- `decision: "block"` + `reason` — Block tool execution or prevent AI from stopping
- `hookSpecificOutput` — Event-specific output, such as modifying tool input (`updatedInput`), overriding tool output (`updatedToolOutput`), or injecting context (`additionalContext`)
See [SDK References](/cli/sdk/references) for full output type definitions.
## Example
### Security Interception (PreToolUse)
Block dangerous shell commands:
```typescript TypeScript
const securityHook: HookCallback = async (input) => {
if (input.hook_event_name !== 'PreToolUse') return {};
if (input.tool_name === 'Bash') {
const cmd = String((input.tool_input as any)?.command ?? '');
if (cmd.includes('rm -rf')) {
return {
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'deny',
permissionDecisionReason: 'Destructive delete operations are not allowed',
},
};
}
}
return {};
};
```
```python Python
async def security_hook(inp: HookInput, tid: str | None, ctx: HookContext) -> HookJSONOutput:
if inp.get("tool_name") == "Bash":
cmd = (inp.get("tool_input") or {}).get("command", "")
if "rm -rf" in cmd:
return {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive delete operations are not allowed",
},
}
return {}
```
### Redact Sensitive Information (PostToolUse)
Override tool output to replace AK/Token and other sensitive information:
```typescript TypeScript
const secretRedactHook: HookCallback = async (input) => {
if (input.hook_event_name !== 'PostToolUse') return {};
const content = typeof input.tool_response === 'string'
? input.tool_response
: JSON.stringify(input.tool_response);
const redacted = content
.replace(/(?:LTAI|AKID)[A-Za-z0-9]{16,}/g, '')
.replace(/Bearer\s+[A-Za-z0-9\-._~+/]+=*/g, 'Bearer ');
if (redacted === content) return {};
return {
hookSpecificOutput: {
hookEventName: 'PostToolUse',
updatedToolOutput: redacted,
},
};
};
```
```python Python
import re
async def secret_redact_hook(inp: HookInput, tid: str | None, ctx: HookContext) -> HookJSONOutput:
if inp.get("hook_event_name") != "PostToolUse":
return {}
response = inp.get("tool_response", "")
content = response if isinstance(response, str) else json.dumps(response)
redacted = re.sub(r"(?:LTAI|AKID)[A-Za-z0-9]{16,}", "", content)
redacted = re.sub(r"Bearer\s+[A-Za-z0-9\-._~+/]+=*", "Bearer ", redacted)
if redacted == content:
return {}
return {
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"updatedToolOutput": redacted,
},
}
```
### Truncate Long Output (PostToolUse)
Trim overly long Bash output, keeping head and tail:
```typescript TypeScript
const bashSummarizeHook: HookCallback = async (input) => {
if (input.hook_event_name !== 'PostToolUse') return {};
if (input.tool_name !== 'Bash') return {};
const content = String(input.tool_response ?? '');
const THRESHOLD = 50 * 1024;
if (content.length <= THRESHOLD) return {};
const head = content.slice(0, 8 * 1024);
const tail = content.slice(-4 * 1024);
const omitted = content.length - head.length - tail.length;
return {
hookSpecificOutput: {
hookEventName: 'PostToolUse',
updatedToolOutput: `${head}\n\n[... OMITTED ${omitted} chars ...]\n\n${tail}`,
},
};
};
```
```python Python
async def bash_summarize_hook(inp: HookInput, tid: str | None, ctx: HookContext) -> HookJSONOutput:
if inp.get("hook_event_name") != "PostToolUse":
return {}
if inp.get("tool_name") != "Bash":
return {}
content = str(inp.get("tool_response") or "")
THRESHOLD = 50 * 1024
if len(content) <= THRESHOLD:
return {}
head = content[:8 * 1024]
tail = content[-4 * 1024:]
omitted = len(content) - len(head) - len(tail)
return {
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"updatedToolOutput": f"{head}\n\n[... OMITTED {omitted} chars ...]\n\n{tail}",
},
}
```
### Force Continuation (Stop)
Prevent the AI from stopping when the task is incomplete:
```typescript TypeScript
const keepGoingHook: HookCallback = async (input) => {
if (input.hook_event_name !== 'Stop') return {};
if (!isTaskComplete()) {
return {
decision: 'block',
reason: 'Please continue completing the remaining tasks',
};
}
return {};
};
```
```python Python
async def keep_going(inp: HookInput, tid: str | None, ctx: HookContext) -> HookJSONOutput:
if inp.get("hook_event_name") != "Stop":
return {}
if not is_task_complete():
return {"decision": "block", "reason": "Please continue completing the remaining tasks"}
return {}
```
### Auto-Approve Permissions (PermissionRequest)
Automatically approve Read tool permission requests:
```typescript TypeScript
const autoApproveRead: HookCallback = async (input) => {
if (input.hook_event_name !== 'PermissionRequest') return {};
if (input.tool_name === 'Read') {
return {
hookSpecificOutput: {
hookEventName: 'PermissionRequest',
decision: { behavior: 'allow' },
},
};
}
return {};
};
```
```python Python
async def auto_approve_read(inp: HookInput, tid: str | None, ctx: HookContext) -> HookJSONOutput:
if inp.get("hook_event_name") != "PermissionRequest":
return {}
if inp.get("tool_name") == "Read":
return {
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {"behavior": "allow"},
},
}
return {}
```
> For the complete permission model, see [Permissions](/cli/sdk/permissions).
### Audit and Security Controls (Combined)
Combine audit logging with security interception:
```typescript TypeScript
import { query } from '@qoder-ai/qoder-agent-sdk';
import type { HookCallback } from '@qoder-ai/qoder-agent-sdk';
import * as fs from 'fs';
const auditLog = fs.createWriteStream('audit.log', { flags: 'a' });
const securityHook: HookCallback = async (input, toolUseID) => {
if (input.hook_event_name === 'PreToolUse') {
// Audit log
auditLog.write(JSON.stringify({
event: 'tool_call',
tool: input.tool_name,
input: input.tool_input,
timestamp: new Date().toISOString(),
}) + '\n');
// Security check: block curl to external domains
if (input.tool_name === 'Bash') {
const cmd = String((input.tool_input as any)?.command ?? '');
if (/curl\s+https?:\/\/(?!localhost)/.test(cmd)) {
return {
hookSpecificOutput: {
hookEventName: 'PreToolUse',
permissionDecision: 'deny',
permissionDecisionReason: 'HTTP requests to external domains are not allowed',
},
};
}
}
}
return {};
};
const result = query({
prompt: 'run deployment',
options: {
hooks: {
PreToolUse: [{ hooks: [securityHook] }],
},
},
});
for await (const message of result) {
// process messages
}
```
```python Python
import json
import logging
import re
from qoder_agent_sdk import query, QoderAgentOptions, HookMatcher
from qoder_agent_sdk.types import HookInput, HookContext, HookJSONOutput
async def security_hook(inp: HookInput, tid: str | None, ctx: HookContext) -> HookJSONOutput:
if inp.get("hook_event_name") != "PreToolUse":
return {}
# Audit log
logging.info(json.dumps({
"event": "tool_call",
"tool": inp.get("tool_name"),
"input": inp.get("tool_input"),
}))
# Security check: block curl to external domains
if inp.get("tool_name") == "Bash":
cmd = str((inp.get("tool_input") or {}).get("command", ""))
if re.search(r"curl\s+https?://(?!localhost)", cmd):
return {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "HTTP requests to external domains are not allowed",
},
}
return {}
async def main():
async for msg in query(
prompt="run deployment",
options=QoderAgentOptions(
hooks={
"PreToolUse": [HookMatcher(hooks=[security_hook])],
},
),
):
pass # process messages
```
---
## Notes
- Hook callbacks should return quickly to avoid blocking AI execution.
- `matcher` matches the `tool_name` field; regex syntax follows each language (JavaScript regex in TypeScript, the `re` module in Python).
- `continue: false` (Python: `continue_: False`) ends the session—effective only for `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `UserPromptSubmit`, `Stop`, and `SubagentStop`; observational events (e.g. `SessionEnd`, `CwdChanged`) ignore it.
- When multiple hooks return conflicting `decision` values, `"deny"` / `"block"` takes precedence (strictest rule wins).
- When multiple hooks set `updatedToolOutput`, the **last non-empty value** wins. For chained transforms (e.g. redact then truncate), execute them sequentially within a single callback.
- The Python SDK uses trailing-underscore field names (`continue_`) to avoid conflicts with Python keywords. The SDK automatically converts them to wire-protocol names (`continue`) during serialization.
# Model Selection
`query()` offers two model-selection modes:
- **Fixed model (default)**: the entire session uses one model.
- **Dynamic selection**: a callback is called before every LLM request to return the model. You can route by purpose (main conversation, sub-agent, context compaction, etc.) or return a BYOK credential to use your own API key.
The two modes are mutually exclusive: passing the callback switches to dynamic-selection mode and the fixed-model setting is ignored.
## Fixed model
Specify it via the model option; omit to use the account default:
```typescript TypeScript
import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: 'Analyze this code',
options: {
auth: qodercliAuth(),
model: 'performance',
},
});
```
```python Python
from qoder_agent_sdk import query, QoderAgentOptions
options = QoderAgentOptions(model="performance")
async for msg in query(prompt="Analyze this code", options=options):
print(msg)
```
## Dynamic selection
Provide a callback function that is invoked before every LLM request:
```typescript TypeScript
import { qodercliAuth, query, type ModelPolicyProvider } from '@qoder-ai/qoder-agent-sdk';
const resolveModel: ModelPolicyProvider = (context) => {
return { model: 'performance' };
};
const q = query({
prompt: 'Analyze this code',
options: {
auth: qodercliAuth(),
resolveModel,
},
});
```
```python Python
from qoder_agent_sdk import query, QoderAgentOptions
from qoder_agent_sdk.types import ModelPolicyContext, ModelPolicyResult, ModelPolicyProvider
resolve_model: ModelPolicyProvider = lambda context: {"model": "performance"}
options = QoderAgentOptions(resolve_model=resolve_model)
async for msg in query(prompt="Analyze this code", options=options):
print(msg)
```
The callback receives the request's purpose, session info, and the list of currently available models.
### Routing by purpose
Use a different model per purpose:
```typescript TypeScript
const resolveModel: ModelPolicyProvider = (context) => {
switch (context.purpose) {
case 'main': return { model: 'performance' };
case 'subagent': return { model: 'efficient' };
case 'compact': return { model: 'lite' };
default: return { model: 'auto' };
}
};
```
```python Python
def resolve_model(context: ModelPolicyContext) -> ModelPolicyResult:
match context.get("purpose"):
case "main": return {"model": "performance"}
case "subagent": return {"model": "efficient"}
case "compact": return {"model": "lite"}
case _: return {"model": "auto"}
```
Purposes cover scenarios like main conversation, sub-agent, context compaction, WebFetch, and image generation. For the full list, see [SDK References](/cli/sdk/references).
### Returning model parameters
Return `parameters` with the selected model to override the context window and thinking depth for that LLM request. These keys are camelCase at the SDK control boundary:
```typescript TypeScript
const resolveModel: ModelPolicyProvider = (context) => {
return {
model: 'ultimate',
parameters: {
contextWindow: 200000,
reasoningEffort: 'high',
},
};
};
```
```python Python
def resolve_model(context: ModelPolicyContext) -> ModelPolicyResult:
return {
"model": "ultimate",
"parameters": {
"contextWindow": 200000,
"reasoningEffort": "high",
},
}
```
These values should match configurations the current model supports. Context-window and thinking metadata are exposed through the callback's `availableModels` input in `ModelInfo.context_config` and `ModelInfo.thinking_config`.
### Timeout
The callback has a default timeout (in milliseconds). Increase it when the callback performs remote I/O:
```typescript TypeScript
{ resolveModel, resolveModelTimeoutMs: 800 }
```
```python Python
options = QoderAgentOptions(
resolve_model=resolve_model,
resolve_model_timeout_ms=800,
)
```
### BYOK: use your own API key
The callback can also return a BYOK credential object — that request will be routed to a third-party provider.
> Before using this feature, please ensure your account has BYOK permission.
```typescript TypeScript
const resolveModel: ModelPolicyProvider = () => ({
model: {
provider: 'bailian',
model: 'qwen3.5-plus-cp',
api_key: process.env.MY_API_KEY!,
},
});
```
```python Python
import os
def resolve_model(context: ModelPolicyContext) -> ModelPolicyResult:
return {
"model": {
"provider": "bailian",
"model": "qwen3.5-plus-cp",
"api_key": os.environ["MY_API_KEY"],
},
}
```
The available provider/model catalog can be fetched at runtime, so the front-end can render selectors and an API-key input.
## Runtime operations
While a session is running you can fetch the account's currently available model list:
```typescript TypeScript
import { qodercliAuth, query } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: '...',
options: { auth: qodercliAuth() },
});
const models = await q.getAvailableModels();
for (const m of models) {
console.log(`${m.value}\t${m.displayName}\t${m.isEnabled ?? true}`);
}
```
```python Python
from qoder_agent_sdk import query, QoderAgentOptions
options = QoderAgentOptions(...)
async with QoderSDKClient(options=options) as client:
models = await client.get_available_models()
for m in models:
print(f"{m['value']}\t{m['displayName']}\t{m.get('isEnabled', True)}")
```
You can also switch the current model in fixed-model mode, or fetch the BYOK provider catalog. For specific method signatures, see [SDK References](/cli/sdk/references).
## Error handling
Dynamic-selection mode has **no automatic fallback** — a callback that times out, throws, or returns an empty model causes the query to fail. Handle errors inside the callback:
```typescript TypeScript
const resolveModel: ModelPolicyProvider = async (context) => {
try {
const policy = await fetchRemotePolicy(context);
return { model: policy.model };
} catch {
return { model: 'auto' }; // fallback, must be non-empty
}
};
```
```python Python
async def resolve_model(context: ModelPolicyContext) -> ModelPolicyResult:
try:
policy = await fetch_remote_policy(context)
return {"model": policy["model"]}
except Exception:
return {"model": "auto"} # fallback, must be non-empty
```
For full field and type definitions, see [SDK References](/cli/sdk/references).
# Cost and usage
Qoder Agent SDK exposes Credits usage data. Credits are Qoder's resource usage unit. This guide explains how to query account quota, request-level Credits, and cumulative session Credits.
For product rules, quota types, and deduction order, see [Credits](/Credits).
## View current context usage
Use `getContextUsage()` / `get_context_usage()` to fetch the live context snapshot without starting an Agent turn. The SDK requests this snapshot from the running CLI and returns it without recalculating usage in the SDK. The response includes overall occupancy, the category estimates shown by the CLI's `/context` view, automatic compaction state, duplicate file reads, session statistics, and displayable skills.
```typescript TypeScript
const usage = await q.getContextUsage();
console.log(`Context used: ${usage.contextWindow.usedPercentage}%`);
for (const skill of usage.skills.items) {
console.log(`${skill.name}: ${skill.percentageOfContext}% of context`);
}
```
```python Python
usage = await client.get_context_usage()
print(f'Context used: {usage["contextWindow"]["usedPercentage"]}%')
for skill in usage["skills"]["items"]:
print(f'{skill["name"]}: {skill["percentageOfContext"]}% of context')
```
All percentage fields use a `0`–`100` scale. Each skill's `percentageOfContext` uses the full context window as its denominator. It is therefore different from the skill tab in the CLI, where a skill's displayed share is relative to all skills.
Category values are local estimates and are not expected to sum exactly to overall occupancy. Use `contextWindow.usedPercentage` for overall occupancy and the category and skill percentage fields for the corresponding breakdowns.
## View Credits usage
Depending on the scope you need, the SDK provides Credits usage for account quotas, individual model requests, and the current session total:
| What you want to view | TypeScript | Python | Scope |
| --------------------------------------- | ------------------------------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------- |
| Account quota and current session usage | `q.getUsageInfo()` | `client.get_usage_info()` | A real-time snapshot of the account and current CLI session |
| Individual model request usage | `message.message.usage` | `message.usage` | One completed model request |
| Current session total | `result.total_credits`, `result.modelUsage` | `result.total_credits`, `result.model_usage` | Cumulative values from the start of the current CLI session through the Result message |
If you only need the current quota in application code and do not want to wait for an Agent task to finish, use `getUsageInfo()` / `get_usage_info()`. To record each model request or settle usage at the end of a session, read the message stream.
In TypeScript, the two session statistics use different naming conventions: `getUsageInfo().session` uses `total_credits` and `model_usage`, while Result messages use `total_credits` and `modelUsage`. Python uses snake\_case in both places.
## Query Credits usage directly
`getUsageInfo()` / `get_usage_info()` returns account quota information and, when available, cumulative Credits for the current CLI session in `session`.
```typescript TypeScript
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
let releaseInput: (() => void) | undefined;
// Keep the CLI session alive without starting an Agent turn.
async function* noPrompt() {
await new Promise((resolve) => {
releaseInput = resolve;
});
}
const q = query({
prompt: noPrompt(),
options: {
auth: accessTokenFromEnv(),
},
});
try {
await q.initializationResult();
const usage = await q.getUsageInfo();
if (usage === null) {
console.log('Usage is unavailable.');
} else {
console.log('Plan:', usage.userType);
console.log('Overall usage:', usage.totalUsagePercentage);
console.log('Plan Credits remaining:', usage.userQuota?.remaining);
if (usage.session) {
console.log('Session Credits:', usage.session.total_credits);
for (const [model, modelUsage] of Object.entries(
usage.session.model_usage,
)) {
console.log(model, modelUsage.credits);
}
}
}
} finally {
releaseInput?.();
await q.close();
}
```
```python Python
import anyio
from qoder_agent_sdk import (
QoderAgentOptions,
QoderSDKClient,
access_token_from_env,
)
async def main():
options = QoderAgentOptions(auth=access_token_from_env())
async with QoderSDKClient(options=options) as client:
usage = await client.get_usage_info()
if usage is None:
print("Usage is unavailable.")
return
print("Plan:", usage.get("userType"))
print("Overall usage:", usage.get("totalUsagePercentage"))
user_quota = usage.get("userQuota") or {}
print("Plan Credits remaining:", user_quota.get("remaining"))
session = usage.get("session")
if session is not None:
print("Session Credits:", session["total_credits"])
for model, model_usage in session["model_usage"].items():
print(model, model_usage["credits"])
anyio.run(main)
```
Common response fields:
| Field | Description |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `userQuota` | Quota included in the current plan, with `total`, `used`, `remaining`, `percentage`, and `unit` |
| `addOnQuota` | Purchased add-on quota; may be absent when the account has no add-on quota. When present, `detailUrl` points to the usage details page |
| `orgResourcePackage` | Shared organization resource package. Uses `cap` for the total quota and provides `used`, `remaining`, `percentage`, `available`, and `unit` |
| `totalUsagePercentage` | Overall usage percentage across all quotas available to the account |
| `isQuotaExceeded` | Whether the account has exhausted its available quota |
| `session.total_credits` | Cumulative Credits for the current CLI session |
| `session.model_usage` | Cumulative Credits for the current session, grouped by model |
Account quota data and `session` are independent. If the account quota service is temporarily unavailable, the SDK may still return an object containing only `session`. Do not use the presence of `userId` or `userQuota` to determine whether session usage is available.
A `null` / `None` result means that neither account quota nor session Credits were available for this request. In addition to an unauthenticated account or an older unsupported CLI version, a failed control request or a temporarily unavailable service can also cause this result.
For the complete API definitions, see [SDK References](/cli/sdk/references).
## Read Credits from session messages
The message stream provides both per-request and cumulative session statistics. The following example prints:
- Credits for each model request from Assistant messages;
- cumulative Credits for the current session from the Result message;
- cumulative Credits grouped by model from the Result message.
One Agent task can trigger multiple model requests, so the stream may contain multiple Assistant messages with request-level Credits. If you only need the current session total, use `total_credits` from the Result message and do not add request-level `credits` to it.
```typescript TypeScript
import { accessTokenFromEnv, query } from '@qoder-ai/qoder-agent-sdk';
for await (const message of query({
prompt: 'Summarize this repository.',
options: {
auth: accessTokenFromEnv(),
},
})) {
if (message.type === 'assistant') {
const usage = message.message.usage;
if (typeof usage?.credits === 'number') {
console.log('Request Credits:', usage.credits);
console.log('Original Credits:', usage.original_credits);
console.log('Billable:', usage.billable);
}
}
if (message.type === 'result') {
if (typeof message.total_credits === 'number') {
console.log('Session Credits:', message.total_credits);
}
for (const [model, modelUsage] of Object.entries(message.modelUsage)) {
if (typeof modelUsage.credits === 'number') {
console.log(model, modelUsage.credits);
}
}
}
}
```
```python Python
import anyio
from qoder_agent_sdk import (
AssistantMessage,
QoderAgentOptions,
ResultMessage,
access_token_from_env,
query,
)
async def main():
options = QoderAgentOptions(auth=access_token_from_env())
async for message in query(
prompt="Summarize this repository.",
options=options,
):
if isinstance(message, AssistantMessage) and message.usage is not None:
credits = message.usage.get("credits")
if credits is not None:
print("Request Credits:", credits)
print("Original Credits:", message.usage.get("original_credits"))
print("Billable:", message.usage.get("billable"))
if isinstance(message, ResultMessage):
if message.total_credits is not None:
print("Session Credits:", message.total_credits)
for model, model_usage in (message.model_usage or {}).items():
credits = model_usage.get("credits")
if credits is not None:
print(model, credits)
anyio.run(main)
```
## Field meanings
| Field | Scope | Description |
| -------------------------------------- | ------------------------ | ---------------------------------------------------------------------------- |
| `credits` | Individual model request | Credits after promotions or discounts are applied |
| `original_credits` | Individual model request | Credits before promotions or discounts are applied; omitted when unavailable |
| `billable` | Individual model request | Whether the request counts toward the user's Credits usage |
| `total_credits` | Current session total | Credits accumulated since the current CLI session started |
| TypeScript `modelUsage[model].credits` | Current session total | Credits accumulated by a specific model in the current session |
| Python `model_usage[model]["credits"]` | Current session total | Credits accumulated by a specific model in the current session |
> **Note:** Do not read request-level Credits from the Result message's `usage` field. Read `credits`, `original_credits`, and `billable` from Assistant messages, and cumulative session Credits from `total_credits` or the per-model statistics.
## Compatibility
- Credits fields are optional for compatibility with older CLI versions. Check that a field exists before reading it, and do not treat a missing value as `0`.
- `total_credits` is a cumulative session value. Do not add the value from multiple Result messages, or usage may be counted more than once.
- Request-level `credits` and cumulative session Credits in a Result message are different scopes for the same consumption. Do not add them together.
- To display remaining account quota, use the quota buckets returned by `getUsageInfo()` / `get_usage_info()` instead of estimating it by adding session messages.
## Next steps
- [Credits](/Credits) — Credits types, deduction order, and ways to view usage
- [SDK References](/cli/sdk/references) — Complete message and control API definitions
# Errors and error codes
Qoder Agent SDK reports task failures, SDK failures, and process exits separately. Handle the most specific signal available instead of treating every non-success condition as an exception.
```text
What failed?
|
+-- Agent completed the task unsuccessfully
| `result` message: subtype, errors, optional error_code
|
+-- SDK could not start or maintain the session
| thrown exception: class, code, and diagnostic fields
|
`-- qodercli process stopped
process exit code: transport-level diagnostic
```
The numeric `error_code` in a Result message and the qodercli process exit code are different namespaces. Do not compare one with values from the other.
## Recommended handling order
1. Consume messages until the SDK produces a `result` or raises an exception.
2. For a Result, check `subtype` and `is_error` first. Use `error_code` only to choose a more specific recovery path when it is present.
3. Catch SDK exceptions around the entire iteration. Use the exception type and fields to diagnose configuration, runtime, or transport failures.
4. Log the session ID, Result subtype, error code, and exception name. Do not log authentication values or full source content by default.
An unsuccessful Result and a later process exception can describe the same failed session. Record both for diagnostics, but avoid showing the user two notifications for one failure.
## Result subtypes
| `subtype` | Meaning | Recommended action |
| ------------------------ | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `success` | The Agent completed the turn | Read `result` and continue or close the session |
| `error_during_execution` | The turn stopped because of an execution, model, service, authentication, or unrecoverable tool error | Read `errors`; use `error_code` when available; retry only when the cause is transient |
| `error_max_turns` | The Agent reached its configured turn limit | Inspect for loops or blocked tools, then increase the limit only if more turns are appropriate |
Future runtimes can add Result subtypes. Always keep a fallback branch that records the subtype and `errors` instead of assuming this table is exhaustive.
## Handle Results
Both SDKs expose an optional numeric `error_code` on Result objects: `SDKResultMessage` in TypeScript and `ResultMessage` in Python. Use the field when it is present, and do not extract a code by parsing human-readable error text.
```typescript TypeScript
import {
QoderCliProcessError,
accessTokenFromEnv,
query,
} from '@qoder-ai/qoder-agent-sdk';
let resultReceived = false;
try {
for await (const message of query({
prompt: 'Run the test suite and explain any failures.',
options: { auth: accessTokenFromEnv() },
})) {
if (message.type !== 'result') continue;
resultReceived = true;
if (message.subtype === 'success' && !message.is_error) {
console.log(message.result);
continue;
}
console.error({
subtype: message.subtype,
errorCode: message.error_code,
errors: message.errors,
sessionId: message.session_id,
});
if (message.error_code === 105) {
// Obtain a new credential and create a new SDK session.
} else if ([500, 10408, 10500].includes(message.error_code ?? -1)) {
// Retry later with bounded exponential backoff.
}
}
} catch (error) {
if (error instanceof QoderCliProcessError) {
console.error({
exitCode: error.exitCode,
signal: error.signal,
stderr: error.stderr,
resultReceived,
});
} else {
throw error;
}
}
```
```python Python
import anyio
from qoder_agent_sdk import (
ProcessError,
QoderAgentOptions,
QoderSDKError,
ResultMessage,
access_token_from_env,
query,
)
async def main() -> None:
options = QoderAgentOptions(auth=access_token_from_env())
result_received = False
try:
async for message in query(
prompt="Run the test suite and explain any failures.",
options=options,
):
if not isinstance(message, ResultMessage):
continue
result_received = True
if message.subtype == "success" and not message.is_error:
print(message.result)
continue
print(
{
"subtype": message.subtype,
"error_code": message.error_code,
"errors": message.errors,
"session_id": message.session_id,
}
)
if message.error_code == 105:
# Obtain a new credential and create a new SDK session.
pass
elif message.error_code in (500, 10408, 10500):
# Retry later with bounded exponential backoff.
pass
except ProcessError as error:
print(
{
"exit_code": error.exit_code,
"stderr": error.stderr,
"result_received": result_received,
}
)
except QoderSDKError as error:
print({"sdk_error": type(error).__name__, "code": getattr(error, "code", None)})
raise
anyio.run(main)
```
## Result error codes
The following numeric codes are normalized by the current qodercli runtime and can appear in `message.error_code` in either SDK. The field is optional. qodercli can also pass through a numeric service code not listed here, so preserve unknown values in logs and fall back to `subtype` plus `errors`.
### Authentication and quota
| Code | Meaning | Recommended action |
| ----: | ----------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `105` | Login or access token expired | Obtain a valid credential and create a new session; register the authentication-expired callback |
| `110` | Daily usage limit reached | Wait for the usage window to reset or review the account limit |
| `113` | Usage quota exhausted | Review quota and plan status; do not immediately retry unchanged |
| `114` | Free-trial account limit reached | Review account eligibility or upgrade options |
| `115` | Free-user quota reached | Wait for quota renewal or review upgrade options |
| `116` | Team administrator Credits exhausted | Ask the team administrator to replenish or adjust Credits |
| `117` | Team member Credits exhausted | Ask the team administrator to assign or replenish Credits |
| `118` | Personal Credits exhausted | Replenish Credits or use an account with available capacity |
| `119` | Free usage limit for the selected model reached | Select an available model, wait for renewal, or review the plan |
| `122` | Billing-group Credits limit reached | Ask the billing administrator to review the group limit |
### Request and policy
| Code | Meaning | Recommended action |
| ------: | ------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `406` | Request blocked because of sensitive content or model refusal | Change the request or input content; do not retry it unchanged |
| `416` | Requested range or request shape is not satisfiable | Inspect `errors`, then reduce or correct the requested range |
| `430` | Requested capability is not supported | Upgrade to compatible SDK/qodercli versions or use a supported capability |
| `47902` | Maximum Agent turns reached | Inspect loops, permissions, and tool failures before increasing the turn limit |
| `48716` | A Hook blocked Agent execution | Inspect the relevant Hook decision and update the Hook or task |
| `80411` | Input content is too long | Reduce the prompt, attachments, or retained context |
| `80412` | Too many images or documents | Reduce the number of media attachments and retry |
### Service and model runtime
| Code | Meaning | Recommended action |
| -------: | ---------------------------------------- | -------------------------------------------------------------------------------- |
| `500` | Request or network failure | Check connectivity and retry with bounded exponential backoff |
| `10408` | Request timed out | Retry with bounded backoff; reduce task scope if timeouts repeat |
| `10500` | Model service internal error | Retry later; retain the session ID when contacting support |
| `10605` | Model request is queued | qodercli normally waits and retries; if the code reaches the Result, retry later |
| `100400` | Custom model service error | Check the custom provider endpoint and service health |
| `100401` | Custom model authentication failed | Refresh or correct the custom provider credential |
| `100403` | Custom model is unavailable or forbidden | Check model access and provider configuration, or select another model |
Retry only errors known to be transient. Use a maximum attempt count, exponential backoff, and jitter. Authentication, quota, policy, input, and configuration errors require a change before retrying.
## SDK exceptions
SDK exceptions mean the application could not configure, start, control, or continue the session. They are separate from an unsuccessful Agent Result.
| Situation | TypeScript | Python | Useful fields |
| -------------------------------------------- | ---------------------------------------- | ----------------------------------------- | ------------------------------------------------------- |
| Authentication not configured | Error with `code: "auth_not_configured"` | Error with `code: "auth_not_configured"` | `code` |
| PAT environment variable missing | `AuthAccessTokenEnvVarError` | `AuthAccessTokenEnvVarError` | `code` |
| Service Account environment variable missing | `AuthServiceAccountEnvVarError` | `AuthServiceAccountEnvVarError` | `code` |
| qodercli not found or cannot start | `QoderCliProcessError` | `CLINotFoundError` / `CLIConnectionError` | message; TypeScript `stderr`; Python path/message |
| qodercli exits unexpectedly | `QoderCliProcessError` | `ProcessError` | `exitCode` / `exit_code`, `stderr`; TypeScript `signal` |
| Model selection callback times out | `ModelPolicyTimeoutError` | `ModelPolicyTimeoutError` | `timeoutMs` / `timeout_ms` |
| Protocol version is incompatible | `ProtocolVersionMismatchError` | `ProtocolVersionMismatchError` | CLI and SDK protocol versions |
| Runtime lacks a required capability | `UnsupportedCliCapabilityError` | `UnsupportedCliCapabilityError` | `capability` |
Machine-readable authentication configuration codes shared by the SDKs are:
| `code` | Meaning |
| --------------------------------------------- | ------------------------------------------------------------- |
| `auth_not_configured` | No authentication method was provided |
| `auth_access_token_env_var_not_configured` | The configured PAT environment variable is absent |
| `auth_service_account_env_var_not_configured` | The configured Service Account environment variable is absent |
For expired credentials reported after startup, use `onAuthExpired` / `on_auth_expired` and create a new session with a valid credential. See [SDK Authentication](/cli/sdk/authentication).
## qodercli process exit codes
Applications using the SDK should normally handle Results and SDK exceptions instead of branching directly on process exit codes. Exit codes are most useful for transport diagnostics or when qodercli is started outside the SDK.
| Exit code | Meaning |
| --------: | ------------------------------------------------------------------------------------------------- |
| `0` | Process exited normally |
| `1` | General or unclassified failure |
| `41` | Authentication failure; the SDK also triggers the authentication-expired callback when configured |
| `42` | Invalid input or command-line arguments |
| `44` | Fatal sandbox error |
| `52` | Fatal configuration error |
| `53` | Fatal turn-limit error |
| `54` | Fatal tool-execution error |
| `130` | Cancellation or interrupt |
Other exit codes or termination signals can come from the operating system, a custom runtime, or a child process. TypeScript exposes them through `QoderCliProcessError.exitCode` and `.signal`; Python exposes an available code through `ProcessError.exit_code`.
## Logging and support
For an actionable failure record, retain:
- SDK language and version
- qodercli version from the `system/init` message, when available
- `session_id`, Result `subtype`, optional `error_code`, and `errors`
- Exception class, machine-readable `code`, process exit code, and signal
- Whether the failure happened before initialization, during a tool call, or after a Result
Redact PATs, Service Account keys, authorization headers, full prompts, source files, and tool output unless they are explicitly required for an approved diagnostic workflow.
## Next steps
- [SDK Authentication](/cli/sdk/authentication) — configure credentials and handle expiry
- [Permissions](/cli/sdk/permissions) — understand tool denial and approval behavior
- [Hooks](/cli/sdk/hooks) — diagnose Hook-blocked execution
- [Session Control](/cli/sdk/session-control) — interrupt and manage running sessions
- [SDK References](/cli/sdk/references) — inspect exact TypeScript and Python types
# SDK References
Qoder Agent SDK ships in two languages: TypeScript and Python. Both SDKs cover the same capability surface, while API signatures, type definitions, and naming follow each language's conventions (camelCase in TypeScript; snake\_case for public options in Python). The full API references are maintained per language:
## By language
| Language | Reference | Package |
| ---------- | ------------------------------------------------------------- | --------------------------- |
| TypeScript | [SDK References - TypeScript](/cli/sdk/references-typescript) | `@qoder-ai/qoder-agent-sdk` |
| Python | [SDK References - Python](/cli/sdk/references-python) | `qoder-agent-sdk` |
## Naming map
Core API mapping between the two SDKs, handy for cross-language migration:
| Capability | TypeScript | Python |
| ------------------------------ | -------------------------------- | ---------------------------- |
| One-shot query | `query()` | `query()` |
| Streaming input | `query()` + async message stream | `QoderSDKClient` |
| Session options | `Options` (`query({ options })`) | `QoderAgentOptions` |
| Auth: PAT from env | `accessTokenFromEnv()` | `access_token_from_env()` |
| Auth: PAT directly | `accessToken()` | `access_token()` |
| Auth: Service Account | `serviceAccount()` | `service_account()` |
| Auth: local login state | `qodercliAuth()` | `qodercli_auth()` |
| Custom tools | `tool()` | `@tool()` decorator |
| In-process MCP server | `createSdkMcpServer()` | `create_sdk_mcp_server()` |
| Permission callback | `canUseTool` | `can_use_tool` |
| Interrupt the current response | `q.interrupt()` | `client.interrupt()` |
| File rewind | `q.rewindFiles()` | `client.rewind_files()` |
| MCP status query | `q.mcpServerStatus()` | `client.get_mcp_status()` |
| Initialization result | `q.initializationResult()` | `client.get_server_info()` |
| Context usage | `q.getContextUsage()` | `client.get_context_usage()` |
| Account and session usage | `q.getUsageInfo()` | `client.get_usage_info()` |
> Note: Python's protocol-level structures—`AgentDefinition`, hooks outputs, settings, etc.—keep the wire-protocol camelCase field names (such as `maxTurns`, `hookSpecificOutput`), unlike the snake\_case public options. See each feature page for details.
## Feature docs
Feature pages carry merged examples for both languages—switch TypeScript / Python inside any code block:
- [Quick Start](/cli/sdk/quick-start)
- [SDK Authentication](/cli/sdk/authentication)
- [Input modes](/cli/sdk/input-modes) / [Session control](/cli/sdk/session-control) / [External session storage](/cli/sdk/session-storage)
- [Streaming output](/cli/sdk/streaming-output) / [Cost and usage](/cli/sdk/cost-usage) / [Model selection](/cli/sdk/model-policy) / [File checkpoint & rewind](/cli/sdk/checkpoint)
- [Tools](/cli/sdk/tools) / [MCP integration](/cli/sdk/mcp) / [Permissions](/cli/sdk/permissions) / [Approval and user input](/cli/sdk/user-input) / [Hooks](/cli/sdk/hooks)
- [Subagents](/cli/sdk/agents) / [Skills](/cli/sdk/skills) / [Plugins](/cli/sdk/plugins)
- [Cloud Agent (experimental)](/cli/sdk/cloud-agent)
# SDK References - TypeScript
## Functions
### `query()`
The SDK's main entry function. Creates an async generator that streams `SDKMessage` in message arrival order.
```typescript
function query(params: {
prompt: string | AsyncIterable;
options?: Options;
}): Query
```
#### Parameters
| Parameter | Type | Description |
| :-------- | :------------------------------------------------------------- | :------------------------------------------------------------------- |
| `prompt` | `string \ | AsyncIterable<`[SDKUserMessage](#sdkusermessage)`>` | Pass a string for single-turn; pass an async iterable for multi-turn |
| `options` | [Options](#options) | Optional session configuration |
#### Return Value
Returns `Query` — an `AsyncGenerator<`[SDKMessage](#sdkmessage)`, void>`, consumed via `for await`.
### `startup()`
Starts the qodercli subprocess and waits for the initialization handshake without sending a user message or starting a model request. Use it to remove CLI startup latency from the first query.
```typescript
function startup(params?: StartupParams): Promise;
```
`initializeTimeoutMs` defaults to `60000`. Initialization errors and timeouts close the subprocess before the promise rejects. The experimental Cloud Agent runtime is not supported.
Each `WarmQuery` accepts exactly one `query()` call. Always call `close()` when the warm session is no longer needed.
```typescript
import { qodercliAuth, startup } from '@qoder-ai/qoder-agent-sdk';
const warm = await startup({
options: {
auth: qodercliAuth(),
cwd: process.cwd(),
},
initializeTimeoutMs: 30_000,
});
try {
const q = warm.query('Summarize this repository.');
for await (const message of q) {
console.log(message);
}
} finally {
warm.close();
}
```
See [StartupParams and WarmQuery](#startupparams-and-warmquery) for the complete types.
### `resolveSettings()`
Reads and merges Qoder settings without starting qodercli. Sources are returned from low to high precedence: `user`, `project`, then `local`.
```typescript
function resolveSettings(
options?: ResolveSettingsOptions,
): Promise;
```
Omit `settingSources` to read all three filesystem sources, or pass `[]` to skip them all. Missing files are skipped; unreadable files, invalid JSON/JSONC, and non-object roots reject the promise.
`effective` is the raw settings cascade, not a complete snapshot of the final runtime configuration. It does not include runtime defaults, query options, environment-placeholder expansion, or workspace-trust decisions.
```typescript
import { resolveSettings } from '@qoder-ai/qoder-agent-sdk';
const resolved = await resolveSettings({
cwd: process.cwd(),
settingSources: ['user', 'project'],
});
console.log(resolved.effective);
console.table(resolved.sources.map(({ source, path }) => ({ source, path })));
```
See [ResolveSettingsOptions and ResolvedSettings](#resolvesettingsoptions-and-resolvedsettings) for the complete types.
### `q.interrupt()`
```typescript
interrupt(): Promise;
```
Stops the current generation or tool execution without closing the session. The optional response lists messages that remain queued. See [Interrupt the current response](/cli/sdk/input-modes#interrupt-the-current-response).
```typescript
type SDKControlInterruptResponse = {
still_queued: string[];
cancelled?: string[];
};
```
### `q.askSideQuestion()`
Asks a question against the current main-session context without interrupting the active generation or tool execution.
```typescript
askSideQuestion(
question: string,
options?: AskSideQuestionOptions,
): Promise;
type SideQuestionHistoryEntry = {
question: string;
response: string;
fallback_notice?: string;
};
type AskSideQuestionOptions = {
signal?: AbortSignal;
history?: readonly SideQuestionHistoryEntry[];
};
type SideQuestionResult = {
response: string;
synthetic: boolean;
refusalFallback?: {
originalModel: string;
fallbackModel: string;
content: string;
};
};
```
`history` supplies earlier side-question exchanges as local context. These entries are not added to the main conversation. Aborting `signal` cancels only this side question; the main Agent turn continues. The method returns `null` when no answer is produced.
```typescript
const answer = await q.askSideQuestion(
'Which configuration file is the current task using?',
{
history: [
{
question: 'What are we investigating?',
response: 'A production login failure.',
},
],
},
);
console.log(answer?.response);
```
While the answer is pending, the normal query stream may emit `system/control_request_progress` messages.
### `q.cancelAsyncMessage()`
```typescript
cancelAsyncMessage(messageUuid: string): Promise;
```
Cancels a queued user message by UUID. Returns `true` when cancelled and `false` when the message is not found or can no longer be cancelled. See [Cancel a queued message](/cli/sdk/input-modes#cancel-a-queued-message).
### `q.backgroundTasks()`
```typescript
backgroundTasks(toolUseId?: string): Promise;
```
Moves an eligible in-flight foreground Agent or Shell execution into the background. Pass a `tool_use` ID to target one execution; omit it to background all eligible executions. When an ID is provided, the method returns `true` only when that execution transitions. The CLI must advertise `background_tasks_v1`.
### `q.stopTask()`
```typescript
stopTask(taskId: string): Promise;
```
Stops one background task without interrupting the main session turn. Use the ID from `task_started.task_id` or `background_tasks_changed.tasks[].task_id`. Agent and Shell tasks share this method and event channel; inspect the open-string `task_type` field (`local_agent` or `local_bash`) when the host needs to distinguish them. The CLI must advertise `background_tasks_v1`.
### `q.initializationResult()`
```typescript
initializationResult(): Promise;
```
Waits for the CLI to finish initializing the current session and returns its initialization snapshot. The result includes commands, agents, skills, and other resources discovered for the session. Its `skills` field is a discovery inventory, not the complete list currently callable by the main session. See [SDKControlInitializeResponse](#sdkcontrolinitializeresponse) for the return type and [Skills](/cli/sdk/skills#reading-skills-discovered-in-the-current-session) for discovery and invocation semantics.
### `q.accountInfo()`
```typescript
accountInfo(): Promise;
```
Returns information about the authenticated Qoder account. The SDK first requests a fresh account snapshot from the current CLI. If an older CLI rejects `account_info`, or the live response is empty, it falls back to the initialization snapshot.
All fields are optional and the result may be empty when account metadata is unavailable. The method does not return access tokens, service-account keys, or other credentials. The experimental Cloud Agent runtime does not support this method. See [AccountInfo](#accountinfo) for the field definitions.
### Session management functions
These functions read or modify local sessions by default. Pass `sessionStore` in their options to operate on an external store. See [External Session Storage](/cli/sdk/session-storage) for setup and behavior.
```typescript
function listSessions(options?: ListSessionsOptions): Promise;
function getSessionInfo(sessionId: string, options?: GetSessionInfoOptions): Promise;
function getSessionMessages(sessionId: string, options?: GetSessionMessagesOptions): Promise;
function renameSession(sessionId: string, title: string, options?: SessionMutationOptions): Promise;
function tagSession(sessionId: string, tag: string | null, options?: SessionMutationOptions): Promise;
function forkSession(sessionId: string, options?: ForkSessionOptions): Promise<{ sessionId: string }>;
function listSubagents(sessionId: string, options?: ListSubagentsOptions): Promise;
function getSubagentMessages(sessionId: string, agentId: string, options?: GetSubagentMessagesOptions): Promise;
function deleteSession(sessionId: string, options?: SessionMutationOptions): Promise;
```
| Function | Purpose | External store requirement |
| :----------------------------- | :-------------------------------------------------- | :--------------------------------------------------------- |
| `listSessions` | List sessions by most recent modification | `SessionStore.listSessions` |
| `getSessionInfo` | Read metadata for one session | `load` |
| `getSessionMessages` | Read the active conversation chain | `load` |
| `renameSession` / `tagSession` | Update the title or tag | `append` |
| `forkSession` | Create an independent session from existing history | `load` and `append` |
| `listSubagents` | List subagent IDs | `SessionStore.listSubkeys` |
| `getSubagentMessages` | Read one subagent's messages | `load`; uses `SessionStore.listSubkeys` when available |
| `deleteSession` | Delete a session and its child data | `SessionStore.delete`; does nothing externally when absent |
The option types share `dir` and `sessionStore`. List and message functions also support pagination through `limit` and `offset`. `listSessions` supports `includeWorktrees` for local sessions. `forkSession` additionally supports `upToMessageId` and `title`; `getSessionMessages` supports `includeSystemMessages`.
### `importSessionToStore()`
Copies an existing local session into an external store.
```typescript
function importSessionToStore(
sessionId: string,
store: SessionStore,
options?: {
dir?: string;
includeSubagents?: boolean;
batchSize?: number;
},
): Promise;
```
`includeSubagents` defaults to `true`. `batchSize` defaults to `500`.
## Types
### `Options`
Configuration object for `query()`.
| Field | Type | Default | Description |
| :-------------------------------- | :-------------------------------------------------------------------------------------------- | :--------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `abortController` | `AbortController` | `undefined` | Ends a session early; calling `abort()` closes the entire session. See [End input and close the session](/cli/sdk/input-modes#ending-input-and-closing-the-session) |
| `additionalDirectories` | `string[]` | `[]` | Additional directories accessible to the AI |
| `agent` | `string` | `undefined` | Agent name used by the main session; see [Agents Reference](#optionsagent) |
| `agents` | `Record` | `undefined` | Programmatically defined subagents; see [Agents Reference](#optionsagents) |
| `allowDangerouslySkipPermissions` | `boolean` | `false` | Allow skipping permission checks; used with `permissionMode: 'bypassPermissions'` |
| `allowedTools` | `string[]` | `[]` | Tool allowlist; listed tools are pre-authorized. Built-in tool names are listed in [Tools Reference](#built-in-tool-list) |
| `auth` | [AuthOptions](#authoptions) | `undefined` | Authentication configuration, **required for `query()`** |
| `canUseTool` | [CanUseTool](#canusetool) | `undefined` | Called when a tool needs approval or the Agent asks the user a question; see [Approval and User Input](/cli/sdk/user-input) |
| `continue` | `boolean` | `false` | Continue the most recent session |
| `customContext` | `Record` | `undefined` | Default custom context for local qodercli inference requests; message-level `custom_context` takes precedence. See limits below |
| `cwd` | `string` | `process.cwd()` | Working directory |
| `disallowedTools` | `string[]` | `[]` | Tool blocklist; priority is higher than `allowedTools` and `permissionMode`. Built-in tool names are listed in [Tools Reference](#built-in-tool-list) |
| `enableFileCheckpointing` | `boolean` | `false` | Enable file checkpointing for use with `rewindFiles()`; see [Checkpoint](/cli/sdk/checkpoint) |
| `env` | `Record` | `process.env` | Environment variables passed to the CLI process; for `QODER_CONFIG_DIR`, see [User data directory](/cli/sdk/session-control#user-data-directory) |
| `proxy` | `string` | `undefined` | Proxy URL for the CLI process; supports `http://`, `https://`, `socks5://`, and `socks://` |
| `executable` | `'bun' \ | 'deno' \ | 'node'` | Auto-detected | JavaScript runtime |
| `executableArgs` | `string[]` | `[]` | Arguments passed to the runtime |
| `experimentalCloudAgent` | [CloudAgentOptions](#cloudagentoptions) | `undefined` | Switch to the Qoder Cloud Agent runtime (experimental); see [Cloud Agent](/cli/sdk/cloud-agent) |
| `extraArgs` | `Record` | `{}` | Additional arguments passed to the CLI |
| `fallbackModel` | `string` | `undefined` | Fallback model when the main model fails |
| `forkSession` | `boolean` | `false` | Fork into a new session ID when used with `resume` |
| `hooks` | `Partial>` | `{}` | Lifecycle hooks; see [Hooks](/cli/sdk/hooks) |
| `includeHookEvents` | `boolean` | `false` | Include hook lifecycle events in the message stream |
| `includePartialMessages` | `boolean` | `false` | Include `stream_event` streaming fragments; see [Streaming Output](/cli/sdk/streaming-output) |
| `maxTurns` | `number` | `undefined` | Maximum conversation turns (tool call round-trips) |
| `mcpServers` | `Record` | `{}` | MCP server configuration; see [MCP](/cli/sdk/mcp) |
| `model` | `string` | CLI default | Model to use; options: `'auto'` / `'ultimate'` / `'performance'` / `'efficient'` / `'lite'` |
| `pathToQoderCLIExecutable` | `string` | Auto-resolved bundled binary | Path to qodercli executable |
| `permissionMode` | [PermissionMode](#permissionmode) | `'default'` | Session permission mode |
| `permissionPromptToolName` | `string` | `undefined` | MCP tool name for permission prompts; mutually exclusive with `canUseTool` |
| `plugins` | [SdkPluginConfig](#sdkpluginconfig)`[]` | `[]` | Load local plugins; see [Plugins](/cli/sdk/plugins) |
| `promptSuggestions` | `boolean` | `false` | Emit `prompt_suggestion` messages after each turn's result |
| `resolveModel` | [ModelPolicyProvider](#modelpolicyprovider) | `undefined` | Dynamic model-selection callback. Passing it switches the query into dynamic-callback mode; see [Model Policy](/cli/sdk/model-policy) |
| `resolveModelTimeoutMs` | `number` | `500` | Callback timeout in milliseconds; only effective when `resolveModel` is passed |
| `resume` | `string` | `undefined` | Session ID to resume |
| `resumeSessionAt` | `string` | `undefined` | Resume from a specified message UUID |
| `resumeDropsTurn` | `string` | `undefined` | With `resumeSessionAt`, require the discarded range to belong to this prompt UUID |
| `persistSession` | `boolean` | `true` | Persist the local session so it can be resumed later. Cannot be `false` when `sessionStore` is set |
| `sessionId` | `string` | Auto-generated | Specify session UUID |
| `sessionStore` | [SessionStore](#sessionstore) | `undefined` | Save session history to external storage so another host can resume it. See [External Session Storage](/cli/sdk/session-storage) |
| `sessionStoreFlush` | [SessionStoreFlush](#sessionstoreflush) | `'batched'` | External write timing. Ignored when `sessionStore` is not set |
| `loadTimeoutMs` | `number` | `60000` | Timeout for each external store read while restoring a session |
| `settings` | `string \ | `[Settings](#settings) | `undefined` | Inline settings object or settings file path |
| `settingSources` | [SettingSource](#settingsource)`[]` | CLI default | Which filesystem settings to load; pass `[]` to skip user/project/local |
| `skills` | `string[] \ | 'all'` | `undefined` | Main-session skill policy; an array restricts model context and invocation, `[]` disables all, and `'all'` enables all; see [Skills](/cli/sdk/skills) |
| `spawnQoderCLIProcess` | `(options: SpawnOptions) => SpawnedProcess` | `undefined` | Custom process spawn function |
| `strictMcpConfig` | `boolean` | `false` | Strict MCP validation |
| `systemPrompt` | `string \ | { type: 'preset'; preset: 'qodercli'; append?: string }` | `undefined` | System prompt. String overrides; preset form appends after qodercli preset |
| `toolConfig` | [ToolConfig](#toolconfig) | `undefined` | Built-in tool behavior configuration; see [Tools](/cli/sdk/tools) |
| `tools` | `string[] \ | { type: 'preset'; preset: 'qodercli' }` | `undefined` | Tool set. When omitted, the SDK default surface includes the persistent Task tools. Pass a string array to restrict available tools; pass an empty array to disable all tools. Built-in tool names are listed in [Tools Reference](#built-in-tool-list) |
#### `customContext`
`customContext` is optional. When omitted, the SDK does not send a custom-context field. The TypeScript public options API uses the camelCase name `customContext`; only the [`SDKUserMessage`](#sdkusermessage) wire message uses the snake\_case name `custom_context`. A message's own `custom_context` overrides the options default; omit the message field to inherit `options.customContext`. The resolved value is used for every inference round in the main session and explicitly invoked child Agents; internal utility-model calls do not inherit it. Messages carrying `custom_context` remain separate and are not coalesced with adjacent messages.
This capability is available only with the local qodercli runtime and is not supported by the Cloud Agent runtime. Backend limits are 1–8 string entries, keys up to 32 Unicode code points, values up to 128 Unicode code points, and at most 1024 UTF-8 bytes for the serialized JSON object. Do not include tokens, Service Account keys, other credentials, email addresses, phone numbers, or personally identifiable information (PII).
The SDK does not validate the content locally. The backend accepts the field only with Service Account authentication and a Qoder VPC deployment. It ignores the entire field without failing inference when the object is invalid or the authentication/deployment requirements are not met. The paired CLI should advertise `custom_context_v1`; an older CLI may ignore the field and emit a compatibility diagnostic.
### `SessionStore`
Interface implemented by external storage adapters. `append` and `load` are required; the other methods enable listing, deletion, and complete subagent restoration.
```typescript
type SessionKey = {
projectKey: string;
sessionId: string;
subpath?: string;
};
type SessionStoreEntry = {
type: string;
uuid?: string;
timestamp?: string;
[key: string]: unknown;
};
interface SessionStore {
append(key: SessionKey, entries: SessionStoreEntry[]): Promise;
load(key: SessionKey): Promise;
listSessions?(projectKey: string): Promise>;
delete?(key: SessionKey): Promise;
listSubkeys?(key: Omit): Promise;
}
```
Treat keys and entries as opaque SDK data. See [External Session Storage](/cli/sdk/session-storage) for behavioral requirements and implementation guidance.
### `SessionStoreFlush`
```typescript
type SessionStoreFlush = 'batched' | 'eager';
```
`batched` writes at result boundaries and is the default. `eager` starts writes more frequently.
### `InMemorySessionStore`
Built-in `SessionStore` implementation for development and tests. It supports all optional methods, plus `getEntries(key)`, `size`, and `clear()`. Its data is process-local and is lost when the process exits.
### `SDKSessionInfo`
Metadata returned by `listSessions()` and `getSessionInfo()`.
```typescript
type SDKSessionInfo = {
sessionId: string;
summary: string;
lastModified: number;
fileSize?: number;
customTitle?: string;
firstPrompt?: string;
gitBranch?: string;
cwd?: string;
tag?: string;
createdAt?: number;
};
```
`fileSize` is available only for local storage. Time fields use Unix epoch milliseconds.
### `SessionMessage`
Historical message returned by session and subagent message functions.
```typescript
type SessionMessage = {
type: 'user' | 'assistant' | 'system';
uuid: string;
session_id: string;
message: unknown;
parent_tool_use_id: string | null;
parent_agent_id: string | null;
timestamp?: string;
subtype?: string;
compact_metadata?: object;
};
```
### `Settings`
`Options.settings` accepts either a settings file path or an inline `Settings` object. The SDK passes these fields to the CLI. The fields below are the skill-related subset; defaults and runtime behavior depend on the paired CLI version.
```typescript
interface Settings {
skillOverrides?: Record<
string,
'on' | 'name-only' | 'user-invocable-only' | 'off'
>;
skillListingMaxDescChars?: number;
skillListingBudgetFraction?: number;
// Other settings fields
}
```
| Field | Description |
| :--------------------------- | :---------------------------------------------------------------------- |
| `skillListingMaxDescChars` | Character limit for each description in the model-visible skill listing |
| `skillListingBudgetFraction` | Fraction of the context window available to the skill listing |
#### `skillOverrides`
Controls discovery and visibility by skill name. Use the plugin-qualified name `plugin:skill` for plugin skills and a bare name for other sources. Matching checks the full name first, then falls back to the bare name.
| Value | Behavior |
| :---------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `'on'` | Default visibility: name and description are visible to the model, with no additional invocation block; session tool and permission policies still apply |
| `'name-only'` | The model sees the name but not the description |
| `'user-invocable-only'` | Hidden from the model; the user can still trigger it through `/name` |
| `'off'` | Hidden from `initializationResult().skills` and model context; `Skill` tool invocation is rejected |
See [Skills](/cli/sdk/skills#hiding-discovered-skills) for complete session-level skill configuration.
### `StartupParams` and `WarmQuery`
```typescript
interface StartupParams {
options?: Options;
initializeTimeoutMs?: number;
}
interface WarmQuery extends AsyncDisposable {
query(prompt: string | AsyncIterable): Query;
close(): void;
}
```
`initializeTimeoutMs` must be a positive finite number and defaults to `60000`. `WarmQuery.query()` can be called once; subsequent calls throw. `close()` is idempotent. `WarmQuery` also implements `Symbol.asyncDispose` for runtimes that support explicit resource management.
### `ResolveSettingsOptions` and `ResolvedSettings`
```typescript
type ResolveSettingsOptions = {
cwd?: string;
settingSources?: Array<'user' | 'project' | 'local'>;
};
type ResolvedSettingSource = 'user' | 'project' | 'local';
type ResolvedSettingsSource = {
source: ResolvedSettingSource;
settings: Settings;
path?: string;
};
type ResolvedSettings = {
effective: Settings;
provenance: Record<
string,
{ source: ResolvedSettingSource; path?: string }
>;
sources: ResolvedSettingsSource[];
};
```
`provenance` records the winning source for each top-level key. Use `sources` when nested settings require per-layer inspection.
### `AccountInfo`
```typescript
type AccountInfo = {
userId?: string;
name?: string;
email?: string;
organization?: string;
organizationName?: string;
subscriptionType?: string;
tokenSource?: string;
apiKeySource?: string;
apiProvider?: 'firstParty' | 'bedrock' | 'vertex' | 'foundry';
};
```
For Qoder-authenticated accounts, `organization` is the organization identifier and `organizationName` is its display name. Authentication-source and provider fields are present only when the paired CLI can determine them.
### `SDKControlInitializeResponse`
Initialization snapshot returned by `q.initializationResult()`.
```typescript
type SDKControlInitializeResponse = {
commands: SlashCommand[];
agents: AgentInfo[];
skills?: Array<{
name: string;
description?: string;
source?: string;
}>;
output_style: string;
available_output_styles: string[];
models: ModelInfo[];
account: AccountInfo;
fast_mode_state?: FastModeState;
};
```
This `skills` field is a discovery inventory with metadata. [SDKSystemMessage.skills](#sdksystemmessage) in the message stream is a `string[]` of names carried by the init message; the two fields do not have the same return structure.
### `AuthOptions`
```typescript
type AuthOptions =
| { type: 'accessToken'; accessToken: string | { envVar: string } }
| { type: 'qodercli' }
| {
type: 'serviceAccount';
serviceAccountKey: string;
}
| {
type: 'serviceAccount';
fetchServiceAccountToken: FetchServiceAccountToken;
};
type ServiceAccountTokenResult = {
token: string;
expiresAt?: number;
};
type FetchServiceAccountToken = () => Promise;
```
`fetchServiceAccountToken` takes no arguments. The host supplies the scope when it obtains a SAT and returns that SAT through `token`. `expiresAt` is optional. When provided, it must be the SAT's absolute expiration time as a Unix timestamp in milliseconds. For example, `Date.now() + 3_600_000` represents one hour from the current time.
| Form | Description |
| :------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------- |
| `{ type: 'accessToken'; accessToken: string }` | Pass PAT directly |
| `{ type: 'accessToken'; accessToken: { envVar } }` | Read PAT from specified environment variable; defaults to `QODER_PERSONAL_ACCESS_TOKEN` |
| `{ type: 'qodercli' }` | Reuse local `qodercli login` session |
| `{ type: 'serviceAccount'; serviceAccountKey: string }` | Use a Service Account key and automatically obtain and refresh short-lived Service Account Tokens (SATs) |
| `{ type: 'serviceAccount'; fetchServiceAccountToken: FetchServiceAccountToken }` | Provide and refresh short-lived Service Account Tokens (SATs) through a host callback |
Convenience constructors: `accessToken(token)` / `accessTokenFromEnv(envVar?)` / `qodercliAuth()` / `serviceAccount({ serviceAccountKey })` / `serviceAccount({ fetchServiceAccountToken })`; see [SDK Authentication](/cli/sdk/authentication).
### `options.agents`
**Type:** `Record`
Registers custom Agents available to the current `query()` session. The object key is the Agent name and the value is that Agent's definition.
> **The `Agent` tool is required**: Custom subagents require the main session to delegate through the built-in `Agent` tool. The Agent tool must be included in `allowedTools` because Qoder invokes subagents through the Agent tool.
```typescript
const q = query({
prompt: 'Use the reviewer agent to inspect recent changes.',
options: {
allowedTools: ['Agent'],
agents: {
reviewer: {
description: 'Reviews code quality and reports actionable findings.',
prompt: 'Review the requested code and report concrete issues.',
tools: ['Read', 'Grep', 'Glob'],
},
},
},
});
```
After registration, the model can invoke these subagents through the built-in `Agent` tool. The main session must include `Agent` in its tool set to delegate work; `allowedTools: ['Agent']` is the required pre-authorization form. If you use `options.tools` to narrow the main session's available tools, include `Agent` there as well.
### `options.agent`
**Type:** `string`
Specifies which Agent identity the main session should run as. The value can be a name registered in `options.agents`, or a built-in / plugin Agent name discovered by the current CLI.
```typescript
const q = query({
prompt: 'Plan the implementation.',
options: {
agents: {
planner: {
description: 'Plans work before implementation.',
prompt: 'Break work into steps, risks, and validation checks.',
tools: ['Read', 'Grep', 'Glob'],
},
},
agent: 'planner',
},
});
```
When set, the main session uses that Agent's `prompt`, `model`, and tool restrictions. When omitted, the session uses the default main-session behavior.
### `AgentDefinition`
Definition of a custom Agent. The fields below are the stable capabilities currently covered and verified by the SDK.
```typescript
type AgentDefinition = {
description: string;
prompt: string;
tools?: string[];
disallowedTools?: string[];
model?: string;
mcpServers?: AgentMcpServerSpec[];
skills?: string[];
initialPrompt?: string;
maxTurns?: number;
effort?: EffortLevel;
permissionMode?: PermissionMode;
};
```
| Field | Type | Required | Description |
| ----------------- | ---------------------- | -------- | ------------------------------------------------------------------------------------------ |
| `description` | `string` | Yes | Agent purpose description; the model uses it to decide when to invoke the Agent |
| `prompt` | `string` | Yes | Agent system prompt |
| `tools` | `string[]` | No | Tool allowlist for this Agent |
| `disallowedTools` | `string[]` | No | Tools excluded from this Agent's tool set |
| `model` | `string` | No | Model override; `'inherit'` means inherit the main session model |
| `mcpServers` | `AgentMcpServerSpec[]` | No | MCP server specs available to this Agent |
| `skills` | `string[]` | No | Skill names preloaded into the Agent context |
| `initialPrompt` | `string` | No | First user input automatically submitted when this Agent is used as the main session Agent |
| `maxTurns` | `number` | No | Maximum API turns for the Agent |
| `effort` | `EffortLevel` | No | Reasoning effort level |
| `permissionMode` | `PermissionMode` | No | Permission mode for tool execution inside this Agent |
#### `description`
Describes what tasks the Agent is suitable for. It affects whether the model chooses this Agent.
```typescript
description: 'Runs project tests, analyzes failing output, and suggests fixes.'
```
Prefer a clear triggering scenario. Avoid broad descriptions such as `Helpful assistant`.
#### `prompt`
The Agent's system prompt. Use it to define the role, constraints, and output format.
```typescript
prompt: `You are a security reviewer.
Check for authentication bypass, authorization bugs, injection risks, and secret leaks.
Return findings sorted by severity.`
```
#### `tools`
Tool allowlist for the Agent. When set, the Agent can only use the listed tools.
```typescript
tools: ['Read', 'Grep', 'Glob']
```
When `tools` is omitted, the subagent default tool set is used. A subagent's tool set does not inherit trimming from the main session's `allowedTools`.
#### `disallowedTools`
Excludes specific tools from the Agent's tool set.
```typescript
disallowedTools: ['Bash', 'Write']
```
When `disallowedTools` is omitted, the subagent does not inherit trimming from the main session's `disallowedTools`. Usually avoid setting both `tools` and `disallowedTools` unless you know the final tool set explicitly.
#### `model`
Specifies the model for the Agent. When omitted, the session default model is used. Supported model tiers include:
| Value | Tier | Description | Suitable for | Credit cost |
| ------------- | ------------- | ------------------------------------------------------------------- | ----------------------------------------------------- | ----------- |
| `auto` | Smart routing | Intelligently selects the best model, balancing capability and cost | Most daily development work; recommended default | \~1.0x |
| `ultimate` | Ultimate | Expert-level deep reasoning and thinking capability | Complex system design and difficult analysis | \~1.6x |
| `performance` | Performance | Advanced reasoning and high-quality output | Core implementation, architecture design, refactoring | \~1.1x |
| `efficient` | Efficient | Standard reasoning with good cost efficiency | Basic code generation, unit tests, daily Q\&A | \~0.3x |
| `lite` | Lite | Basic reasoning, free to use | Quick validation, simple logic, quick questions | 0x |
Agents also support two special forms:
| Value | Description |
| ------------- | ------------------------------------------------------------------ |
| `inherit` | Inherit the main session model |
| Full model ID | Directly specify a model ID supported by the current CLI / backend |
#### `mcpServers`
Limits or adds MCP servers available to this Agent.
```typescript
type AgentMcpServerSpec =
| string
| Record;
```
The string form references an MCP server already configured in the session. The object form configures a dedicated MCP server for this Agent. For the MCP server configuration shape, see [SDK References - McpServerConfig](#mcpserverconfig).
#### `skills`
List of skill names to preload into the Agent context. Plain skill names and plugin-qualified names are both supported.
```typescript
skills: ['review', 'sdk-test-plugin:sdk-echo']
```
For session-level skill behavior, see [Skills](/cli/sdk/skills).
#### `initialPrompt`
Automatically submitted as the first user input when this Agent becomes the main session Agent through `options.agent`.
```typescript
initialPrompt: 'Start by scanning authentication and session management code.'
```
This field only takes effect for the main session Agent. It is ignored when the Agent is invoked as a subagent through the `Agent` tool.
#### `maxTurns`
Limits the Agent's maximum API turns. Use it to control cost, execution time, and loop risk.
```typescript
maxTurns: 6
```
#### `effort`
```typescript
type EffortLevel = 'low' | 'medium' | 'high' | 'max';
```
Controls the Agent's reasoning effort level. Higher `effort` is usually suitable for complex reviews, architecture analysis, and high-risk changes, but increases latency and token usage.
#### `permissionMode`
Controls the permission mode for tool execution inside this Agent. It uses the same semantics as the session-level `permissionMode`, but its scope is limited to this Agent. For the session-level permission chain, `allowedTools` / `disallowedTools` / `canUseTool` priority, and examples, see [Permission Control](/cli/sdk/permissions#controlling-default-policy-permissionmode).
```typescript
type PermissionMode =
| 'default'
| 'acceptEdits'
| 'bypassPermissions'
| 'yolo'
| 'plan'
| 'dontAsk'
| 'auto';
```
| Value | Meaning | Suitable for |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `'default'` | Standard permission behavior. Tool calls still pass through tool sets, allow / deny rules, runtime approval, or CLI default policy | Most interactive subagents |
| `'acceptEdits'` | Automatically accepts file-edit operations; other sensitive operations still follow the permission flow | A subagent that is approved to modify workspace files |
| `'bypassPermissions'` | Skips permission checks. High-risk mode, usually only for trusted automation or test environments | Controlled CI, temporary validation, one-off automation |
| `'yolo'` | Compatibility alias for `'bypassPermissions'`; also skips permission checks | Compatibility with older configs; not recommended for new code |
| `'plan'` | Plan mode. Suitable for producing a plan first; by default it does not perform real changes | Planning, design, review, or cases where the subagent should not modify files |
| `'dontAsk'` | Does not ask interactively; operations that are not pre-authorized or allowed by rules are denied | Non-interactive environments, or workflows that should fail instead of prompting |
| `'auto'` | Runtime capability decides allow or deny automatically; safe workspace file edits may be auto-allowed | Reduce confirmation interruptions while retaining runtime judgment |
For permission semantics, see [Permission Control](/cli/sdk/permissions).
### `AgentInfo`
Agent summary returned by `q.supportedAgents()`.
```typescript
type AgentInfo = {
name: string;
description: string;
model?: string;
};
```
| Field | Type | Description |
| ------------- | --------------------- | ------------------------------------------------------------------------- |
| `name` | `string` | Agent name |
| `description` | `string` | Agent purpose description |
| `model` | `string \ | undefined` | Agent model override; usually empty when unset or when `model: 'inherit'` |
```typescript
const q = query({
prompt: 'List agents.',
options: {
agents: {
reviewer: {
description: 'Reviews code quality.',
prompt: 'Review code and report findings.',
},
},
},
});
const agents = await q.supportedAgents();
```
The returned list may include Agents registered through `options.agents`, and may also include built-in, project, user, or plugin Agents discovered by the current CLI. The actual available entries depend on the qodercli version and current configuration.
### Context and Invocation Boundaries
- Subagents use independent context and do not receive the parent session's full history.
- The main information passed from the parent session to a subagent is the task prompt supplied to the `Agent` tool.
- A subagent's intermediate tool results do not directly enter the parent session; the parent session receives the subagent's final response.
- Subagents cannot spawn their own subagents, so do not put `Agent` in a subagent's `tools`.
- `initialPrompt` only takes effect for the main session Agent specified by `options.agent`.
---
### Model Policy
Dynamic model-selection capability of `query()`. Two modes: fixed-model (no `resolveModel`, uses `options.model` or backend default) and dynamic-callback (pass `resolveModel`, the callback decides the model before every LLM call). For full concepts, triggers and error handling see [Model Policy](/cli/sdk/model-policy).
#### `options.resolveModel`
**Type:** [ModelPolicyProvider](#modelpolicyprovider)
Entry point for dynamic-callback mode. Once passed, dynamic-callback mode is enabled and the SDK calls this callback before every LLM request to fetch the model. The `model` returned by the callback is the final model for that request; **there is no automatic fallback**.
#### `options.resolveModelTimeoutMs`
**Type:** `number`, default `500`
Callback timeout, in milliseconds. On timeout [ModelPolicyTimeoutError](#modelpolicytimeouterror) is thrown and the query fails (no fallback). Only effective when `resolveModel` is passed.
### `ModelPolicyProvider`
Callback function signature. May be synchronous or asynchronous.
```typescript
type ModelPolicyProvider = (
context: ModelPolicyContext,
) => ModelPolicyResult | Promise;
```
Triggering scenarios are distinguished by [QoderModelPurpose](#qodermodelpurpose):
| Scenario | `purpose` | Notes |
| ------------------ | ------------- | ---------------------------------------------------------------------------------- |
| Main conversation | `'main'` | Re-invoked between turns / tools — a session may trigger many times |
| Subagent | `'subagent'` | Subagents share the same provider |
| WebFetch tool | `'web_fetch'` | After WebFetch retrieves content, a second LLM call summarises it |
| ImageGen tool | `'image_gen'` | Used to pick the image-generation model |
| Context compaction | `'compact'` | Before compaction starts, the callback is queried for the compaction model |
| BYOK | any | Set `model` to a [CustomModel](#custommodel) object to route via a third-party LLM |
Behavioural notes:
- The callback may be triggered many times within a single session (re-invoked before every turn / tool / sub-task).
- The `model` returned by the callback is the final model for that request; the SDK does not re-validate it.
- Throwing an exception or returning an empty `model` fails the query. See [Model Policy — Error handling](/cli/sdk/model-policy#error-handling).
### `ModelPolicyContext`
The context passed to the callback on every invocation.
```typescript
interface ModelPolicyContext {
purpose: QoderModelPurpose;
sessionId: string;
availableModels: ModelInfo[];
}
```
| Field | Type | Required | Description |
| ----------------- | --------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `purpose` | [QoderModelPurpose](#qodermodelpurpose) | yes | Purpose of this LLM call |
| `sessionId` | `string` | yes | Current session ID; the same value is passed across callback invocations within a session, so it can be used as a cache / telemetry key |
| `availableModels` | [ModelInfo](#modelinfo)`[]` | yes | The models currently available to the account, supplied by the CLI on every `get_model_policy` request |
### `QoderModelPurpose`
```typescript
type QoderModelPurpose =
| 'main'
| 'subagent'
| 'web_fetch'
| 'image_gen'
| 'compact';
```
| Value | Triggering scenario |
| ------------- | ---------------------------------------------------- |
| `'main'` | Main-conversation LLM call |
| `'subagent'` | Subagent call |
| `'web_fetch'` | Secondary LLM call triggered by the WebFetch tool |
| `'image_gen'` | Image-generation call triggered by the ImageGen tool |
| `'compact'` | Context compaction / summarisation |
### `ModelPolicyResult`
The callback's return value.
```typescript
interface ModelPolicyResult {
model: string | (CustomModel & { model: string });
parameters?: Record;
}
```
| Field | Type | Required | Description |
| ------------ | --------------------------------------------------------------- | ---------------------------------------------------- | --------------------------------------------------------------------- |
| `model` | `string \ | (`[CustomModel](#custommodel)` & { model: string })` | yes | String: model identifier; object: BYOK credentials + model identifier |
| `parameters` | `Record` | no | Per-request model-parameter overrides. SDK control keys use camelCase |
Supported `parameters` keys:
| Key | Type | Description |
| ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `contextWindow` | `number` | Context-window size in tokens for this LLM request. Choose a value supported by the selected model, usually from [ModelInfo.context\_config](#modelcontextconfig) |
| `reasoningEffort` | `string` | Thinking / reasoning depth for this LLM request. Choose a level supported by the selected model, usually from [ModelInfo.thinking\_config](#modelthinkingconfig). Common levels include `none`, `low`, `medium`, `high`, `xhigh`, and `max` |
`model` forms:
- **String** — any model ID supported by the backend (such as `auto` / `performance` / `glm51`); the exact set of valid values is returned in real time by [q.getAvailableModels()](#qgetavailablemodels). Must be **non-empty**, otherwise the query fails.
- **`CustomModel` object** (BYOK) — the SDK extracts the object's `model` field as the model identifier for this call, and forwards the remaining fields as credentials to the CLI for routing to a third-party LLM.
### `CustomModel`
BYOK credentials. In the `resolveModel` callback, set the `model` field to this object directly, and that LLM request will be routed to a third-party provider.
```typescript
interface CustomModel {
provider: string;
model: string;
api_key: string;
style?: string;
}
```
| Field | Type | Required | Description |
| ---------- | -------- | -------- | -------------------------------------------------------------------------------- |
| `provider` | `string` | yes | Provider key — must match a [BYOKProviderInfo.key](#byokproviderinfo) |
| `model` | `string` | yes | Model identifier — extracted by the SDK as the model ID for this call |
| `api_key` | `string` | yes | The API Key supplied by the user |
| `style` | `string` | no | Upstream protocol style, e.g. `"openai"` / `"anthropic"`; defaults to `"openai"` |
Notes:
- `provider` must match a `key` in the catalog, otherwise backend authentication fails.
- A wrong `api_key` causes authentication to fail, which fails the query directly (dynamic-callback mode does not fall back).
- BYOK calls report `total_cost_usd` as 0 on the platform; token usage is reported as-is and billed by the provider.
### BYOK catalog types
The provider/model catalog returned by [q.listByokProviders()](#qlistbyokproviders).
```typescript
interface SDKControlGetByokConfigResponse {
providers: BYOKProviderInfo[];
}
interface BYOKProviderInfo {
key: string;
display_name: string;
api_key_url: string;
types: BYOKModelTypeInfo[];
}
interface BYOKModelTypeInfo {
key?: string;
display_name: string;
models: BYOKModelInfo[];
}
interface BYOKModelInfo {
key: string;
display_name: string;
is_vl: boolean;
is_reasoning: boolean;
format: string;
max_input_tokens: number;
}
```
#### `BYOKProviderInfo`
| Field | Type | Description |
| -------------- | --------------------- | -------------------------------------------------------- |
| `key` | `string` | Provider key — fill into `CustomModel.provider` for BYOK |
| `display_name` | `string` | Display name |
| `api_key_url` | `string` | URL pointing the user where to obtain an API Key |
| `types` | `BYOKModelTypeInfo[]` | Model groups under this provider |
#### `BYOKModelTypeInfo`
| Field | Type | Description |
| -------------- | --------------------- | -------------------------------------------- |
| `key` | `string \ | undefined` | Group key, common values: `cp` / `tp` / `pg` |
| `display_name` | `string` | Group display name |
| `models` | `BYOKModelInfo[]` | Models within the group |
#### `BYOKModelInfo`
| Field | Type | Description |
| ------------------ | --------- | ----------------------------------------------- |
| `key` | `string` | Model ID — fill into `CustomModel.model` |
| `display_name` | `string` | Display name |
| `is_vl` | `boolean` | Whether vision / multi-modal input is supported |
| `is_reasoning` | `boolean` | Whether this is a reasoning model |
| `format` | `string` | Upstream protocol format (e.g. `openai`) |
| `max_input_tokens` | `number` | Maximum input token count |
### `ModelInfo`
Summary of an available model returned by [q.getAvailableModels()](#qgetavailablemodels). Also used as the element type of [ModelPolicyContext.availableModels](#modelpolicycontext).
```typescript
interface ModelInfo {
value: string;
displayName: string;
description: string;
isEnabled: boolean;
isNew?: boolean;
isFree?: boolean;
priceFactor?: number;
serverScene?: string;
context_config?: ModelContextConfig;
thinking_config?: ModelThinkingConfig;
promotion?: ModelPromotion;
serverModel?: ServerModelJson;
}
```
| Field | Type | Description |
| ----------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `value` | `string` | Model identifier — usable as [ModelPolicyResult.model](#modelpolicyresult) or [q.setModel()](#qsetmodel) argument |
| `displayName` | `string` | Display name |
| `description` | `string` | Model description text |
| `isEnabled` | `boolean` | Whether currently available |
| `isNew` | `boolean \ | undefined` | Whether this is a newly launched model |
| `isFree` | `boolean \ | undefined` | Whether this is a free model |
| `priceFactor` | `number \ | undefined` | Price factor |
| `serverScene` | `string \ | undefined` | Original top-level key in the server model-list response before client-side merging, such as `assistant` or `byok_enterprise` |
| `context_config` | [ModelContextConfig](#modelcontextconfig) `\ | undefined` | Context-window configuration (tier label -> token count) |
| `thinking_config` | [ModelThinkingConfig](#modelthinkingconfig) `\ | undefined` | Thinking / reasoning configuration |
| `promotion` | [ModelPromotion](#modelpromotion) `\ | undefined` | Promotion / discount info from the model list API; absent means no promotion |
| `serverModel` | [ServerModelJson](#servermodeljson) `\ | undefined` | Raw model entry from the model list API, forwarded verbatim by the CLI |
### `ModelContextConfig`
Context-window configuration keyed by tier label, such as `"200K"` or `"1M"`.
```typescript
type ModelContextConfig = Record;
interface ModelContextWindowEntry {
token_count: number;
is_default?: boolean;
}
```
| Field | Type | Description |
| ------------- | ---------------------- | -------------------------------- |
| `token_count` | `number` | Token count for this tier |
| `is_default` | `boolean \ | undefined` | Whether this is the default tier |
### `ModelThinkingConfig`
Thinking / reasoning configuration for a model.
```typescript
interface ModelThinkingConfig {
disabled?: ModelThinkingDisabled;
enabled?: ModelThinkingEnabled;
}
interface ModelThinkingDisabled {
description?: string;
}
interface ModelThinkingEnabled {
description?: string;
efforts?: Record;
is_default?: boolean;
}
interface ModelEffortEntry {
description?: string;
is_default?: boolean;
}
```
| Field | Type | Description |
| ----------------- | ----------------------------------------------- | -------------------------------------------------------------------------------- |
| `disabled` | `ModelThinkingDisabled \ | undefined` | Configuration shown when thinking is disabled |
| `enabled` | `ModelThinkingEnabled \ | undefined` | Configuration shown when thinking is enabled, including effort levels |
| `enabled.efforts` | `Record \ | undefined` | Per-effort metadata, such as `"low"` / `"high"` descriptions and default markers |
### `ModelPromotion`
Promotion / discount info forwarded from the model list API. Nested field names stay in the server's snake\_case form.
```typescript
type LocalizedModelText = {
en?: string;
zh?: string;
} & Record;
interface ModelPromotion {
active: boolean;
badge?: LocalizedModelText;
description?: LocalizedModelText;
discount_factor?: number;
before_promotion_price_factor?: number;
timezone?: string;
rule_id?: string;
window_start?: string;
window_end?: string;
}
```
| Field | Type | Description |
| ------------------------------- | --------------------------------- | -------------------------------------------------------- |
| `active` | `boolean` | Whether the promotion is currently active for this model |
| `badge` | `LocalizedModelText \ | undefined` | Short localized label |
| `description` | `LocalizedModelText \ | undefined` | Longer localized description |
| `discount_factor` | `number \ | undefined` | Discounted price factor while the promotion is active |
| `before_promotion_price_factor` | `number \ | undefined` | Original price factor before the promotion |
| `timezone` | `string \ | undefined` | IANA timezone used to evaluate the promotion window |
| `rule_id` | `string \ | undefined` | Server rule identifier |
| `window_start` | `string \ | undefined` | Daily window start, in `HH:mm` format |
| `window_end` | `string \ | undefined` | Daily window end, in `HH:mm` format |
### `ServerModelJson`
Raw JSON-compatible model entry from the model list API. Use this when a server field is needed before it has a first-class `ModelInfo` field.
```typescript
type ServerModelJson = Record;
```
### `SDKControlGetContextUsageResponse`
Current context occupancy and the same locally estimated category data shown by the CLI's `/context` view. Returned by [q.getContextUsage()](#qgetcontextusage).
```typescript
type SDKControlGetContextUsageResponse = {
model: string;
contextWindow: {
usedPercentage: number;
};
categories: Array<{
type:
| 'system_prompt'
| 'system_tools'
| 'skills'
| 'messages'
| 'other'
| 'free_space'
| 'auto_compact';
percentage: number;
}>;
autoCompact: {
enabled: boolean;
thresholdPercentage: number;
};
skills: {
count: number;
percentageOfContext: number;
items: Array<{
name: string;
source: 'project' | 'user' | 'built-in' | 'plugin';
percentageOfContext: number;
}>;
};
duplicateFileReads: Array<{
path: string;
count: number;
}>;
session: {
messageCount: number;
promptCount: number;
toolCalls: { total: number; succeeded: number; failed: number };
linesChanged: { added: number; removed: number };
};
};
```
All percentages use a `0`–`100` scale. `skills.percentageOfContext` and every skill item's `percentageOfContext` use the full context window as the denominator, not the aggregate size of all skills.
The SDK requests this snapshot from the running CLI and does not recalculate it client-side. Category values are local estimates and are not expected to add up exactly to `contextWindow.usedPercentage`. Use `contextWindow.usedPercentage` for overall occupancy and the category and skill percentage fields for the corresponding breakdowns.
### `UsageInfo`
Account quota and usage snapshot returned by [q.getUsageInfo()](#qgetusageinfo).
```typescript
interface UsageInfo {
userId?: string;
userType?: string;
totalUsagePercentage?: number;
isHighestTier?: boolean;
expiresAt?: number;
upgradeUrl?: string;
userQuota?: UsageQuotaBucket;
addOnQuota?: UsageAddOnQuotaBucket;
isQuotaExceeded?: boolean;
isPlanQuotaProrated?: boolean;
orgResourcePackage?: UsageOrgResourcePackage;
session?: SessionCreditsUsage;
}
interface UsageQuotaBucket {
total?: number;
used?: number;
remaining?: number;
percentage?: number;
unit?: string;
}
interface UsageAddOnQuotaBucket extends UsageQuotaBucket {
detailUrl?: string;
}
interface UsageOrgResourcePackage {
used?: number;
cap?: number;
remaining?: number;
percentage?: number;
available?: boolean;
unit?: string;
}
type SessionCreditsUsage = {
total_credits: number;
model_usage: Record;
};
```
| Field | Type | Description |
| ---------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `userId` | `string \ | undefined` | Account identifier |
| `userType` | `string \ | undefined` | Plan tier (e.g. `free`, `pro`, `teams`) |
| `totalUsagePercentage` | `number \ | undefined` | Overall usage across all buckets, `0`–`100` |
| `isHighestTier` | `boolean \ | undefined` | Whether the account is already on the highest plan |
| `expiresAt` | `number \ | undefined` | Current plan/quota expiry, Unix epoch milliseconds |
| `upgradeUrl` | `string \ | undefined` | Upgrade page URL, when an upgrade is available |
| `userQuota` | `UsageQuotaBucket \ | undefined` | Included plan quota bucket |
| `addOnQuota` | `UsageAddOnQuotaBucket \ | undefined` | Purchased add-on quota bucket, when the account has add-on quota (`detailUrl` links to the usage page) |
| `isQuotaExceeded` | `boolean \ | undefined` | Whether all available quota is exhausted |
| `isPlanQuotaProrated` | `boolean \ | undefined` | Whether the plan quota is prorated for the current period |
| `orgResourcePackage` | `UsageOrgResourcePackage \ | undefined` | Organization-shared resource package (`available` indicates it can be drawn from) |
| `session` | `SessionCreditsUsage \ | undefined` | Cumulative Credits for the current CLI session; may still be present when the account quota request fails |
Each bucket reports `used` / `remaining` / `percentage` against its `total` (or `cap` for the org package) in `unit` (typically `credits`).
Missing fields, or fields with an unexpected runtime type, are omitted from the returned object.
`session.total_credits` is the cumulative value for the current CLI session, and `session.model_usage` contains cumulative Credits grouped by model. This `model_usage` field uses snake\_case; the corresponding Result message field is `modelUsage`.
### `ModelPolicyTimeoutError`
```typescript
class ModelPolicyTimeoutError extends Error {}
```
Thrown by the SDK when the `resolveModel` callback exceeds `options.resolveModelTimeoutMs` without returning. The query fails directly, with no fallback.
### `q.setModel()`
```typescript
setModel(model?: string): Promise;
```
Switches the model for fixed-model mode at runtime. Takes effect on the next LLM call. Effective only in fixed-model mode; in dynamic-callback mode, calling it does not override the callback's result. Valid model IDs: see [ModelInfo.value](#modelinfo).
### `q.getAvailableModels()`
```typescript
getAvailableModels(): Promise;
```
Fetches the latest model list available to the current account in real time. Always returns the latest result, no caching; returns an empty array (does not throw) when the list cannot be fetched temporarily. In dynamic-callback mode, [ModelPolicyContext.availableModels](#modelpolicycontext) already carries the same up-to-date list, so calling this method explicitly is unnecessary.
### `q.listByokProviders()`
```typescript
listByokProviders(): Promise;
```
Returns the BYOK provider/model catalog available to the current account as an array:
- Returns `null`: the CLI does not support this API (graceful fallback, no exception).
- Returns an array (may be empty): the list of providers available to the current account (an empty array means the account has not enabled BYOK).
Field semantics: see [BYOK catalog types](#byok-catalog-types).
### `q.getContextUsage()`
```typescript
getContextUsage(): Promise;
```
Fetches a live context snapshot from the running CLI. This does not start an Agent turn, so it can be used to update a context meter while an interactive session remains open.
```typescript
const usage = await q.getContextUsage();
console.log(`Context used: ${usage.contextWindow.usedPercentage}%`);
for (const skill of usage.skills.items) {
console.log(`${skill.name}: ${skill.percentageOfContext}% of context`);
}
```
Return type: see [SDKControlGetContextUsageResponse](#sdkcontrolgetcontextusageresponse).
### `q.getUsageInfo()`
```typescript
getUsageInfo(): Promise;
```
Fetches the current account's quota information and cumulative Credits for the current CLI session from the running CLI in real time.
- Returns `null`: no account quota or session Credits were available for this request. An unauthenticated account, an older unsupported CLI version, or a failed control request can gracefully fall back to `null` without throwing.
- Returns a [UsageInfo](#usageinfo) object: the known account quota and usage fields whose runtime types are valid. Missing or invalid fields are omitted; if the account quota request fails, the object may still contain only `session`.
```typescript
import { query, qodercliAuth } from '@qoder-ai/qoder-agent-sdk';
const q = query({
prompt: userMessages(),
options: { auth: qodercliAuth() },
});
const usage = await q.getUsageInfo();
if (usage) {
console.log(`Plan: ${usage.userType}, used ${usage.totalUsagePercentage}%`);
console.log(`Plan quota: ${usage.userQuota?.remaining}/${usage.userQuota?.total} ${usage.userQuota?.unit} left`);
console.log(`Session credits: ${usage.session?.total_credits}`);
}
```
Return type: see [UsageInfo](#usageinfo). For complete examples covering account quota, request-level Credits, and cumulative session Credits, see [Cost and usage](/cli/sdk/cost-usage).
---
### `CanUseTool`
For an ordinary tool, the callback runs only when user approval is required; tools that were automatically allowed or denied do not trigger it. `AskUserQuestion` is the exception: after the callback is configured, it is called for a real user answer unless user interaction has been explicitly disabled.
```typescript
type CanUseTool = (
toolName: string,
input: Record,
options: CanUseToolOptions,
) => Promise;
```
#### `CanUseToolOptions`
```typescript
type CanUseToolOptions = {
signal: AbortSignal;
suggestions?: PermissionUpdate[];
blockedPath?: string;
decisionReason?: string;
decisionReasonType?: PermissionDecisionReasonType;
classifierApprovable?: boolean;
title?: string;
displayName?: string;
description?: string;
toolUseID: string;
agentID?: string;
exitPlanMode?: ExitPlanModeApprovalDetails;
};
```
| `options` Field | Type | Description |
| :-------------------------------------- | :----------------------------- | :---------------------------------------------------------------------- |
| `signal` | `AbortSignal` | Aborted when cancelled |
| `suggestions` | `PermissionUpdate[]` | Permission update suggestions from CLI |
| `blockedPath` | `string` | File path triggering authorization (file-related scenarios only) |
| `decisionReason` | `string` | Human-readable authorization reason from CLI |
| `decisionReasonType` | `PermissionDecisionReasonType` | Permission reason classification |
| `classifierApprovable` | `boolean` | Whether the current call can be auto-approved by the runtime classifier |
| `title` / `displayName` / `description` | `string` | Human-readable authorization text generated at runtime |
| `toolUseID` | `string` | This tool invocation's ID |
| `agentID` | `string` | Sub-Agent ID initiating the call |
| `exitPlanMode` | `ExitPlanModeApprovalDetails` | Approval details for exiting plan mode |
For complete permission configuration, see [Permission Control](/cli/sdk/permissions#runtime-approval-canusetool). For callback timing and `AskUserQuestion`, see [Approval and User Input](/cli/sdk/user-input).
### `PermissionMode`
```typescript
type PermissionMode =
| 'default'
| 'acceptEdits'
| 'bypassPermissions'
| 'yolo'
| 'plan'
| 'dontAsk'
| 'auto';
```
| Value | Meaning | Suitable for |
| :-------------------- | :----------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------- |
| `'default'` | Standard permission behavior. Tool calls are handled by `tools`, allow / deny rules, dynamic approval, or runtime policy | Most interactive sessions |
| `'acceptEdits'` | Automatically accepts file-edit operations; other sensitive operations still follow the permission flow | Sessions that are approved to modify workspace files |
| `'bypassPermissions'` | Skips permission checks; must also set `allowDangerouslySkipPermissions: true` | Trusted automation or test environments |
| `'yolo'` | Compatibility alias for `'bypassPermissions'`; must also set `allowDangerouslySkipPermissions: true` | Compatibility with older configs; not recommended for new code |
| `'plan'` | Plan mode. Suitable for producing a plan first; by default it does not perform real changes | Planning, design, review |
| `'dontAsk'` | Does not ask interactively; operations that are not pre-authorized or allowed by rules are denied | Non-interactive environments, or workflows that should fail instead of prompting |
| `'auto'` | Runtime capability decides allow or deny automatically; safe workspace file edits may be auto-allowed | Reduce confirmation interruptions while retaining runtime judgment |
For more details, see [Permission Control](/cli/sdk/permissions#controlling-default-policy-permissionmode).
### `PermissionResult`
Return value of `CanUseTool`.
```typescript
type PermissionResult =
| {
behavior: 'allow';
updatedInput?: Record;
updatedPermissions?: PermissionUpdate[];
toolUseID?: string;
decisionClassification?: PermissionDecisionClassification;
}
| {
behavior: 'deny';
message: string;
interrupt?: boolean;
toolUseID?: string;
decisionClassification?: PermissionDecisionClassification;
};
```
`allow.updatedInput` replaces the actual parameters the tool receives when modified. `deny.interrupt: true` denies and also interrupts the Agent.
### `McpServerConfig`
MCP server configuration, passed to `Options.mcpServers`.
```typescript
type McpServerConfig =
| McpStdioServerConfig
| McpSSEServerConfig
| McpHttpServerConfig
| McpSdkServerConfigWithInstance;
```
#### `McpStdioServerConfig`
```typescript
type McpStdioServerConfig = {
type?: 'stdio';
command: string;
args?: string[];
env?: Record;
};
```
#### `McpSSEServerConfig`
```typescript
type McpSSEServerConfig = {
type: 'sse';
url: string;
headers?: Record;
};
```
#### `McpHttpServerConfig`
```typescript
type McpHttpServerConfig = {
type: 'http';
url: string;
headers?: Record;
};
```
#### `McpSdkServerConfigWithInstance`
```typescript
type McpSdkServerConfigWithInstance = {
type: 'sdk';
name: string;
instance: McpServer;
};
```
Returned by the `createSdkMcpServer()` factory; see [MCP - In-Process Server](/cli/sdk/mcp#in-process-server-recommended).
### `SdkPluginConfig`
Load local plugins.
```typescript
type SdkPluginConfig = {
type: 'local';
path: string;
};
```
| Field | Type | Description |
| :----- | :-------- | :------------------------------------------------ |
| `type` | `'local'` | Currently only local is supported |
| `path` | `string` | Absolute or relative path to the plugin directory |
### `CloudAgentOptions`
Type of `Options.experimentalCloudAgent`. Configures the agent / session reference for the Cloud runtime; full usage in [Cloud Agent](/cli/sdk/cloud-agent).
```typescript
type CloudAgentOptions =
| {
session: { id: string };
agent?: never;
stream?: CloudAgentStreamOptions;
}
| {
agent: CloudAgentReference;
session: { create: CloudSessionCreateParams };
stream?: CloudAgentStreamOptions;
};
type CloudAgentReference =
| { id: string; create?: never }
| { create: AgentCreateParams; id?: never };
type CloudAgentStreamOptions = {
afterId?: string;
deltaFlushIntervalMs?: number;
};
```
| Field | Type | Description |
| :---------------------------- | :---------------------------------------------------- | :-------------------------------------------------------------------- |
| `agent.id` | `string` | Reuse an existing Cloud Agent; mutually exclusive with `agent.create` |
| `agent.create` | [AgentCreateParams](#agentcreateparams) | Create a new Cloud Agent; mutually exclusive with `agent.id` |
| `session.id` | `string` | Reuse an existing Cloud session; `agent` must not be passed |
| `session.create` | [CloudSessionCreateParams](#cloudsessioncreateparams) | Create a new Cloud session; `environment_id` is required |
| `stream.afterId` | `string` | SSE replay anchor — start after this event ID |
| `stream.deltaFlushIntervalMs` | `number` | Delta merge / flush interval, in milliseconds |
### `AgentCreateParams`
Request body for creating a new Cloud Agent, matching the agent-create fields of the Qoder Cloud OpenAPI.
```typescript
type AgentCreateParams = {
model: string;
name: string;
description?: string | null;
system?: string | null;
tools?: Array<{
type: 'agent_toolset_20260401';
enabled_tools?: Array<
| 'bash'
| 'write'
| 'glob'
| 'web_fetch'
| 'read'
| 'edit'
| 'grep'
| 'web_search'
>;
}>;
mcp_servers?: Array<{ name: string; type: 'url'; url: string }>;
skills?: Array<{ skill_id: string; type: 'custom' }>;
metadata?: Record;
};
```
| Field | Type | Description |
| :------------ | :----------------------- | :------------------------------------------------------------------------------------------------------ |
| `model` | `string` | Model identifier. Accepted values: `'auto'` / `'ultimate'` / `'performance'` / `'efficient'` / `'lite'` |
| `name` | `string` | Human-readable agent name |
| `description` | `string \ | null` | Description |
| `system` | `string \ | null` | System prompt |
| `tools` | see above | Built-in toolset; `enabled_tools` controls the allowlist |
| `mcp_servers` | see above | URL-based MCP server connections |
| `skills` | see above | User-defined custom skills |
| `metadata` | `Record` | Arbitrary key-value metadata |
### `CloudSessionCreateParams`
Request body for creating a new Cloud session.
```typescript
type CloudSessionCreateParams = {
environment_id: string;
resources?: Array<{ type: 'file'; file_id: string; path?: string }>;
title?: string | null;
vault_ids?: Array;
memory_store_ids?: Array;
};
```
| Field | Type | Description |
| :----------------- | :--------------- | :------------------------------------------------------------------- |
| `environment_id` | `string` | Container environment ID; **required** |
| `resources` | see above | Resources mounted into the session container (currently only `file`) |
| `title` | `string \ | null` | Session title |
| `vault_ids` | `string[]` | Credential vault IDs |
| `memory_store_ids` | `string[]` | Memory store IDs |
### `SettingSource`
Controls which filesystem settings are loaded.
```typescript
type SettingSource = 'user' | 'project' | 'local';
```
| Value | Meaning | Location |
| :---------- | :------------------------------------------- | :--------------------------- |
| `'user'` | User-level global settings | `~/.qoder/settings.json` |
| `'project'` | Project shared settings (version controlled) | `.qoder/settings.json` |
| `'local'` | Project local settings (gitignored) | `.qoder/settings.local.json` |
When omitted, all sources are loaded per CLI defaults; pass `[]` to skip entirely.
### `ToolConfig`
Built-in tool behavior configuration.
```typescript
type ToolConfig = {
askUserQuestion?: {
previewFormat?: 'markdown' | 'html';
};
};
```
### Built-in Tool List
In `tools`, `allowedTools`, `disallowedTools`, `canUseTool`, hook matchers, and Agent tool allowlists, built-in tools use the runtime tool names in the table below.
| Category | Tool name | Description |
| ----------------- | ------------------ | ------------------------------------------------------------------- |
| Command execution | `Bash` | Execute shell commands |
| File operations | `Read` | Read file contents |
| File operations | `Edit` | Edit files by string matching |
| File operations | `Write` | Create or overwrite files |
| Search | `Glob` | Search by filename pattern |
| Search | `Grep` | Search by content regex |
| Network | `WebFetch` | Fetch and process URL content |
| Network | `WebSearch` | Web search |
| Agent | `Agent` | Invoke a subagent |
| Interaction | `AskUserQuestion` | Ask the user a question |
| Notebook | `NotebookEdit` | Edit notebook cells |
| Persistent tasks | `TaskCreate` | Create a task |
| Persistent tasks | `TaskGet` | Retrieve task details |
| Persistent tasks | `TaskUpdate` | Update task fields, status, and dependencies |
| Persistent tasks | `TaskList` | List tasks |
| Background tasks | `TaskOutput` | Send output to a background task |
| Background tasks | `TaskStop` | Stop a background task |
| Plan / worktree | `ExitPlanMode` | Exit plan mode |
| Plan / worktree | `EnterWorktree` | Enter a git worktree |
| Plan / worktree | `ExitWorktree` | Exit a worktree |
| Config | `Config` | Read or write configuration |
| Todo fallback | `TodoWrite` | Replaces the persistent Task tools when `QODER_FEATURE_TASKS=false` |
| MCP resources | `ListMcpResources` | List MCP resources |
| MCP resources | `ReadMcpResource` | Read an MCP resource |
| MCP invocation | `Mcp` | Generic MCP tool call |
Custom MCP tool names use this format:
```text
mcp__{serverName}__{toolName}
```
### `tool()`
Creates a type-safe SDK MCP tool definition.
```typescript
function tool(
name: string,
description: string,
inputSchema: Schema,
handler: (
args: InferShape,
extra: RequestHandlerExtra,
) => Promise,
extras?: ToolExtras,
): SdkMcpToolDefinition;
```
| Parameter | Type | Required | Meaning | Current Qoder behavior |
| ------------- | ------------------------------------------ | -------- | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | `string` | Yes | Unique tool identifier within the current MCP server | Forms the model-visible full tool name `mcp__{serverName}__{name}`; registration requires it to be non-empty |
| `description` | `string` | Yes | Tool description shown to the model; describe when to use it, what it does, and what it returns | Forwarded into the tool list and directly affects whether the model calls the tool correctly; registration requires it to be non-empty |
| `inputSchema` | `Schema extends AnyZodRawShape` | Yes | Zod raw shape defining tool input parameters | The SDK uses it to generate the MCP input schema and infer handler `args` as `InferShape` |
| `handler` | `(args, extra) => Promise` | Yes | Async function executed when the tool is called | Executed by the SDK when the model calls the tool; the return value is sent back to the model as a tool result |
| `extras` | `ToolExtras` | No | Extra tool metadata, currently used for `annotations` | The SDK registers supported annotations on the MCP server; this does not replace permission configuration |
`tool()` itself is a factory for defining tools. Registration constraints such as non-empty `name`, non-empty `description`, and duplicate tool names are validated by `createSdkMcpServer()` when tools are registered.
#### `AnyZodRawShape`
```typescript
type AnyZodRawShape = ZodRawShapeCompat;
```
`AnyZodRawShape` is compatible with Zod 3 / Zod 4. It represents a field object, not `z.object(...)`.
#### `InferShape`
```typescript
type InferShape = ShapeOutput;
```
`InferShape` infers the handler `args` type from the Zod raw shape.
#### `SdkMcpToolDefinition`
```typescript
type SdkMcpToolDefinition<
Schema extends AnyZodRawShape = AnyZodRawShape,
> = {
name: string;
description: string;
inputSchema: Schema;
annotations?: ToolAnnotations;
handler: (
args: InferShape,
extra: RequestHandlerExtra,
) => Promise