<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Serghei Iakovlev</title>
    <description>The latest articles on DEV Community by Serghei Iakovlev (@serghei).</description>
    <link>https://dev.to/serghei</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F39633%2Fe7186a63-3266-435b-a7e1-056d42058fa0.jpg</url>
      <title>DEV Community: Serghei Iakovlev</title>
      <link>https://dev.to/serghei</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/serghei"/>
    <language>en</language>
    <item>
      <title>From GitHub Issue to Pull Request: Running Claude Code Unattended</title>
      <dc:creator>Serghei Iakovlev</dc:creator>
      <pubDate>Mon, 27 Jul 2026 15:42:39 +0000</pubDate>
      <link>https://dev.to/serghei/from-github-issue-to-pull-request-running-claude-code-unattended-2d6o</link>
      <guid>https://dev.to/serghei/from-github-issue-to-pull-request-running-claude-code-unattended-2d6o</guid>
      <description>&lt;p&gt;You already run Claude Code by hand: copy issues into a prompt, watch it work, check the diff, and if something breaks halfway through, you restart it. This works fine for one task at a time, but it falls apart when you have 10 tasks simultaneously.&lt;/p&gt;

&lt;p&gt;Claude Code is good at handling routine engineering tasks: bug fixes, dependency bumps, and small features, when the prompt is clear and the task is scoped. But when it comes to scaling, you need an infrastructure with isolated workspaces, retry logic, state that survives a restart, and tracker integration, not to waste time on babysitting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/sortie-ai/sortie" rel="noopener noreferrer"&gt;Sortie&lt;/a&gt; removes the manual work. You label an issue, Sortie picks it up, creates an isolated workspace, runs the agent, retries it if it stalls, and opens a pull request when it's done. This article describes how to set the entire process from an empty directory to a GitHub issue turning into a PR without you touching the keyboard in between.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you need
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A GitHub repository you control&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Export two environment variables:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt; - authenticates Claude Code&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GITHUB_TOKEN&lt;/code&gt; - it's read by &lt;code&gt;tracker.api_key: $GITHUB_TOKEN&lt;/code&gt; for polling/updating issues, and it's the same token &lt;code&gt;gh pr create&lt;/code&gt; inside the &lt;code&gt;after_run&lt;/code&gt; hook uses to open the PR, so it needs Issues: read/write, Contents: read, and Pull requests: read/write scopes on that repository, all on one fine-grained PAT.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Push access to the repository over SSH. The &lt;code&gt;after_create&lt;/code&gt; hook below clones with &lt;code&gt;git@github.com:...&lt;/code&gt;, so git authenticates with your SSH key, not with &lt;code&gt;GITHUB_TOKEN&lt;/code&gt;. Verify with &lt;code&gt;ssh -T git@github.com&lt;/code&gt;. If you'd rather stay on one credential, swap the clone URL for &lt;code&gt;https://${GITHUB_TOKEN}@github.com/yourorg/yourrepo.git&lt;/code&gt; and give the token Contents: read/write.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In your repository, create the &lt;code&gt;agent-ready&lt;/code&gt; label — you need it to exist before you can put it on an issue, and &lt;code&gt;query_filter&lt;/code&gt; finds nothing without it. Creating &lt;code&gt;in-progress&lt;/code&gt;, &lt;code&gt;review&lt;/code&gt;, and &lt;code&gt;done&lt;/code&gt; up front is also worth doing: GitHub does create a missing label when Sortie applies it, but it comes out in default gray, and the colors are yours to pick.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Claude Code installed on your machine. Verify with command: &lt;code&gt;claude --version&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The entire process takes about 15 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;To install Sortie on Linux or macOS, run the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://get.sortie-ai.com/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Homebrew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--cask&lt;/span&gt; sortie-ai/tap/sortie
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows, use the PowerShell equivalent. It runs on the PowerShell 5.1 that ships with Windows 10 and 11, as well as on PowerShell 7:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'https://get.sortie-ai.com/install.ps1'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one installs into &lt;code&gt;%LOCALAPPDATA%\Programs\sortie&lt;/code&gt;, so it needs no administrator rights, and it adds the directory to your user &lt;code&gt;PATH&lt;/code&gt; for you. Shells you already have open keep their old environment, so reopen PowerShell before continuing.&lt;/p&gt;

&lt;p&gt;Sortie is a single Go binary file, for which you need no database server, Docker, or Node.js. State lives in an embedded SQLite file (&lt;code&gt;.sortie.db&lt;/code&gt;) that Sortie creates next to your workflow file — no need to create it manually.&lt;/p&gt;

&lt;p&gt;Confirm it's on your &lt;code&gt;PATH&lt;/code&gt; by running the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sortie &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring WORKFLOW.md
&lt;/h2&gt;

&lt;p&gt;This file contains everything you need for Sortie, including trackers to pull tasks from, agents to run, and prompts telling them what to do. Create a directory and a file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;tracker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github&lt;/span&gt;
  &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$GITHUB_TOKEN&lt;/span&gt;
  &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yourorg/yourrepo&lt;/span&gt;
  &lt;span class="na"&gt;query_filter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;label:agent-ready"&lt;/span&gt;
  &lt;span class="na"&gt;active_states&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;agent-ready&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;in-progress&lt;/span&gt;
  &lt;span class="na"&gt;in_progress_state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;in-progress&lt;/span&gt;
  &lt;span class="na"&gt;handoff_state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;review&lt;/span&gt;
  &lt;span class="na"&gt;terminal_states&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;done&lt;/span&gt;

&lt;span class="na"&gt;polling&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;interval_ms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30000&lt;/span&gt;

&lt;span class="na"&gt;workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./workspaces&lt;/span&gt;

&lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;after_create&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;git clone --depth 1 git@github.com:yourorg/yourrepo.git .&lt;/span&gt;
  &lt;span class="na"&gt;before_run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;git fetch origin main&lt;/span&gt;
    &lt;span class="s"&gt;git checkout -B "sortie/${SORTIE_ISSUE_IDENTIFIER}" origin/main&lt;/span&gt;
  &lt;span class="na"&gt;after_run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;git add -A&lt;/span&gt;
    &lt;span class="s"&gt;git diff --cached --quiet || \&lt;/span&gt;
      &lt;span class="s"&gt;git commit -m "sortie(${SORTIE_ISSUE_IDENTIFIER}): automated changes"&lt;/span&gt;
    &lt;span class="s"&gt;git push origin "sortie/${SORTIE_ISSUE_IDENTIFIER}" --force-with-lease&lt;/span&gt;
    &lt;span class="s"&gt;gh pr create --fill \&lt;/span&gt;
      &lt;span class="s"&gt;--head "sortie/${SORTIE_ISSUE_IDENTIFIER}" \&lt;/span&gt;
      &lt;span class="s"&gt;--base main 2&amp;gt;/dev/null || true&lt;/span&gt;
  &lt;span class="na"&gt;timeout_ms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;120000&lt;/span&gt;

&lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude-code&lt;/span&gt;
  &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;claude&lt;/span&gt;
  &lt;span class="na"&gt;max_turns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;max_concurrent_agents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;turn_timeout_ms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1800000&lt;/span&gt;
  &lt;span class="na"&gt;stall_timeout_ms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;300000&lt;/span&gt;

&lt;span class="na"&gt;claude-code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;permission_mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bypassPermissions&lt;/span&gt;
  &lt;span class="na"&gt;max_budget_usd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;max_turns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;

&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8888&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

You are a senior engineer working in this repository. Your work is tracked by
an automated orchestrator (Sortie) that manages your session, retries failures,
and monitors progress.

&lt;span class="gu"&gt;## Task&lt;/span&gt;

&lt;span class="gs"&gt;**#{{ .issue.identifier }}**&lt;/span&gt;: {{ .issue.title }}
{{ if .issue.description }}

&lt;span class="gu"&gt;### Description&lt;/span&gt;

{{ .issue.description }}
{{ end }}
{{ if .issue.url }}

&lt;span class="gs"&gt;**Ticket:**&lt;/span&gt; {{ .issue.url }}
{{ end }}

&lt;span class="gu"&gt;## Rules&lt;/span&gt;
&lt;span class="p"&gt;
1.&lt;/span&gt; Read existing code and project conventions before writing anything new.
&lt;span class="p"&gt;2.&lt;/span&gt; Keep changes minimal. Implement exactly what the task requires.
&lt;span class="p"&gt;3.&lt;/span&gt; Run the project's lint and test commands before finishing. All checks must pass.
&lt;span class="p"&gt;4.&lt;/span&gt; Write tests for new functionality, covering edge cases, not just the happy path.
{{ if not .run.is_continuation }}

&lt;span class="gu"&gt;## First run&lt;/span&gt;

Start by understanding the codebase structure. Check for existing patterns
and follow them. Write the implementation, add a test, and verify everything passes.
{{ end }}
{{ if .run.is_continuation }}

&lt;span class="gu"&gt;## Continuation (turn {{ .run.turn_number }}/{{ .run.max_turns }})&lt;/span&gt;

You are resuming this task. Run &lt;span class="sb"&gt;`git status`&lt;/span&gt; and check test output to understand
the current state. Continue from where the previous turn left off. Do not repeat
work already completed.
{{ end }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file consists of two parts. Everything between the two --- markers is YAML front matter for configuration. Everything after the closing --- is a Go text/template, rendered separately for each issue and sent to the agent as its prompt.&lt;/p&gt;

&lt;p&gt;In this file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;query_filter: "label:agent-ready"&lt;/code&gt; - Sortie only takes issues with this label. If the label is missing, it ignores the issue.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;active_states&lt;/code&gt; / &lt;code&gt;in_progress_state&lt;/code&gt; / &lt;code&gt;handoff_state&lt;/code&gt; / &lt;code&gt;terminal_states&lt;/code&gt; - a status map through GitHub labels. &lt;code&gt;active_states&lt;/code&gt; must include &lt;code&gt;in_progress_state&lt;/code&gt;, otherwise Sortie refuses to start and &lt;code&gt;sortie validate&lt;/code&gt; fails with a config error (enforced in code). &lt;code&gt;handoff_state&lt;/code&gt; must not match any of &lt;code&gt;active_states&lt;/code&gt; or &lt;code&gt;terminal_states&lt;/code&gt; (also enforced in code).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;agent.max_turns: 5&lt;/code&gt; - how many turns the orchestrator runs within one session: the first turn plus up to four continuations. Defaults to 20.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;claude-code.max_turns: 50&lt;/code&gt; - how many internal steps Claude Code itself takes in a single invocation. These are two different fields that happen to share a name, in different sections. At 5x50, that's up to 250 steps per task.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;claude-code.max_budget_usd: 5&lt;/code&gt; - a cost cap per invocation, not per session. Sortie passes &lt;code&gt;--max-budget-usd&lt;/code&gt; on every turn and Claude Code's counter starts from zero each time, so with &lt;code&gt;agent.max_turns: 5&lt;/code&gt; the worst case for one issue is five turns of $5, not $5 total. The cap is also checked at the turn boundary rather than mid-turn, so a single turn can overshoot it. To bound one issue, size it as &lt;code&gt;budget x max_turns&lt;/code&gt; and lower one of the two.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;permission_mode: bypassPermissions&lt;/code&gt; - lets the agent act without stopping to ask for approval on each step; run it against a repository you control. Setting it explicitly is the right move, but omitting it does not make the run interactive: the adapter then falls back to the deprecated &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;, which bypasses the same checks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before running the config, do the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;yourorg/yourrepo&lt;/code&gt; with your repository (URL cloning) in &lt;code&gt;tracker.project&lt;/code&gt; and &lt;code&gt;hooks:after_create&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;On Windows, adapt the hooks: they run through &lt;code&gt;cmd.exe /C&lt;/code&gt; rather than &lt;code&gt;sh -c&lt;/code&gt;, so write &lt;code&gt;%SORTIE_ISSUE_IDENTIFIER%&lt;/code&gt; instead of &lt;code&gt;${SORTIE_ISSUE_IDENTIFIER}&lt;/code&gt; and drop the trailing &lt;code&gt;\&lt;/code&gt; line continuations.&lt;/li&gt;
&lt;li&gt;Check the file for mistakes using the command: &lt;code&gt;sortie validate ./WORKFLOW.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Running the test issue
&lt;/h2&gt;

&lt;p&gt;Create a test issue with the &lt;code&gt;agent-ready&lt;/code&gt; label and add the description, for example, “Add a /healthz endpoint returning 200” — the more specific your description is, the more specific result you get.&lt;/p&gt;

&lt;p&gt;Run the &lt;code&gt;sortie ./WORKFLOW.md&lt;/code&gt; and watch the running process in the dashboard.&lt;/p&gt;

&lt;p&gt;All git operations are Sortie's hooks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;after_create&lt;/code&gt; — clones the repository into an isolated workspace under its working directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;before_run&lt;/code&gt; — creates the &lt;code&gt;sortie/&amp;lt;issue-identifier&amp;gt;&lt;/code&gt; branch off &lt;code&gt;origin/main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;after_run&lt;/code&gt; — stages, commits, pushes, and runs &lt;code&gt;gh pr create --fill&lt;/code&gt; to open the actual PR.&lt;/li&gt;
&lt;li&gt;After that, Sortie swaps the &lt;code&gt;in-progress&lt;/code&gt; label for &lt;code&gt;review&lt;/code&gt;. The &lt;code&gt;agent-ready&lt;/code&gt; label is already gone by then — Sortie replaced it with &lt;code&gt;in-progress&lt;/code&gt; back when it picked the issue up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In its turn, Claude Code edits the file in the isolated workspace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;If a run doesn’t go smoothly, here’s what happens, and how Sortie recovers on its own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retries.&lt;/strong&gt; A failed or stalled turn goes into a retry queue with exponential backoff, up to &lt;code&gt;agent.max_retry_backoff_ms&lt;/code&gt; (5 minutes by default). The issue tries again on its own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stalls.&lt;/strong&gt; If the agent goes quiet mid-session without events and output for longer than &lt;code&gt;stall_timeout_ms&lt;/code&gt; (5 minutes by default), Sortie treats the session as dead, kills it, and requeues the issue for retry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost control.&lt;/strong&gt; &lt;code&gt;claude-code.max_budget_usd&lt;/code&gt; caps spend per session, independent of how many turns it takes. Combine it with &lt;code&gt;agent.max_concurrent_agents&lt;/code&gt; to bound total exposure across everything running at once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State survives restarts.&lt;/strong&gt; Retry timers, run history, and session metadata live in a SQLite file next to &lt;code&gt;WORKFLOW.md&lt;/code&gt;. If you kill the process and start it again, nothing is lost, and nothing gets dispatched twice.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s next
&lt;/h2&gt;

&lt;p&gt;To switch the agent, change the line: swap &lt;code&gt;agent.kind: claude-code&lt;/code&gt; for &lt;code&gt;codex&lt;/code&gt;, &lt;code&gt;copilot-cli&lt;/code&gt;, &lt;code&gt;opencode&lt;/code&gt;, or &lt;code&gt;kiro&lt;/code&gt;, and the tracker configuration stays exactly as it is.&lt;/p&gt;

&lt;p&gt;Jira, Linear, and Gitea work the same way on the tracker side - same file, different &lt;code&gt;tracker.kind&lt;/code&gt;. Sortie also supports a CI feedback loop, where a failing check on the opened PR gets routed back to the agent instead of left for you to notice.&lt;/p&gt;

&lt;p&gt;For full configuration reference and adapter details, check &lt;a href="https://docs.sortie-ai.com" rel="noopener noreferrer"&gt;docs.sortie-ai.com&lt;/a&gt;. Source and issue tracker: &lt;a href="https://github.com/sortie-ai/sortie" rel="noopener noreferrer"&gt;github.com/sortie-ai/sortie&lt;/a&gt;.&lt;/p&gt;

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