Automating... Kiro CLI invocations

Kiro CLI is great and most people use it in the interactive mode without knowing that there is also... non interactive mode, which you can use to supercharge your everyday operations.

It works like that:

~> kiro-cli chat -r -a --no-interactive "say hello"
All tools are now trusted (!). Kiro will execute tools without asking for confirmation.
Agents can sometimes do unexpected things so understand the risks.

Learn more at https://kiro.dev/docs/cli/chat/security/#using-tools-trust-all-safely



> Hello!

 ▸ Credits: 0.22 • Time: 3s

Now, we used -r option to resume last conversation so when we invoke it again:

~> kiro-cli chat -r -a --no-interactive "have i asked you to say hello already?"
All tools are now trusted (!). Kiro will execute tools without asking for confirmation.
Agents can sometimes do unexpected things so understand the risks.

Learn more at https://kiro.dev/docs/cli/chat/security/#using-tools-trust-all-safely



> Yes, just a moment ago you asked me to "say hello" and I responded with "Hello!".

 ▸ Credits: 0.12 • Time: 5s

It remembers the context of the conversation. As you probably noticed we also get notification of tools usage, it's due to -a flag - I did it on purpose to show you that you can ask it to execute some things for you:

~> kiro-cli chat -r -a --no-interactive "create a test.txt file with hello world content and then calculate md5 for it"
All tools are now trusted (!). Kiro will execute tools without asking for confirmation.
Agents can sometimes do unexpected things so understand the risks.

Learn more at https://kiro.dev/docs/cli/chat/security/#using-tools-trust-all-safely



I will run the following command: echo "hello world" > ~/test.txt && md5sum ~/test.txt (using tool: shell)

6f5902ac237024bdd0c176cb93063dc4  /home/luktom/test.txt
 - Completed in 0.6s

> Done. File created at ~/test.txt with content hello world.

MD5: 6f5902ac237024bdd0c176cb93063dc4

 ▸ Credits: 0.25 • Time: 9s

Now you probably started to notice how you can use it in your scripts for making non-obvious decisions for example, or for dynamic exploration of data like logs. I'll leave you the use cases, let's go back to original idea of automating it.

Let's automate...

... but first you may ask "why?". The reason is simple - from my observations tools like Kiro CLI work better when they have couple of turns with individual instructions rather than a single prompt, even the complex ones and structured correctly. Of course it's changing and the whole mechanism is getting better with every version, like recently Kiro CLI thinks a lot more before implementing any requested feature, nevertheless we can still use our "automation" to get better results.

input=$(cat <<'EOF'
look at current project structure and conventions
implement feature XX that works in a way: xxxxxxx; also add tests for that and make sure they work
make sure it is implemented correctly
make sure tests are passing
are there any cases which you missed?
add the tests for them
update the docs
commit and push
EOF
)

while IFS= read -r line; do
  if [[ -n "$line" ]]; then
    kiro-cli chat -r -a --no-interactive "$line"
  fi
done <<<"$input"

So now just describe the feature and paste it in the project catalog and instantly get better process of ensuring your code works 😄

And parallelize

So when you are already excited with above trick, let's go further and implement multiple things in the project simultaneously, but before we do so, I need to share some Kiro CLI "secret" with you, that I found during the testing of the method:

Kiro CLI uses -r in the context of a directory you execute it in - that means if you run above "automation" twice in the same catalog it'll quickly get confused as two parallel conversations are "merged".

So you may think "symlink" - I tested that, doesn't work, hard links also, the only trick that seems to work is... to use a bind mounts:

mkdir -p "$workspace_dir"
sudo mount --bind "$base_project" "$workspace_dir" 2>/dev/null

Ugly as it requires sudo but it works when you want to use the exact same codebase.

Final beta script

So let's combine all we learnt today as a single script:

#!/bin/bash

conversation_id="$1"
shift

if [[ -z "$conversation_id" ]]; then
  echo "Usage: $0 <conversation_id> [commands...]"
  exit 1
fi

if [[ -n "$*" ]]; then
  input=$(echo -e "$*")
else
  input=$(cat)
fi

base_project=$(pwd)
workspace_dir="$base_project/.kiro/workspaces/$conversation_id"

mkdir -p "$workspace_dir"
sudo mount --bind "$base_project" "$workspace_dir" 2>/dev/null

cleanup() {
  cd "$base_project"
  sudo umount "$workspace_dir" 2>/dev/null
}
trap cleanup EXIT

cd "$workspace_dir" || exit 1

while IFS= read -r line; do
  if [[ -n "$line" ]]; then
    output=$(kiro-cli chat -r -a --no-interactive "$line" 2>&1 | awk '/Learn more at/{flag=1; next} flag')
    echo "$output" | sed '/./,$!d' | sed -e :a -e '/^\s*$/{$d;N;ba' -e '}' | sed '$s/\x1b\[[0-9;?]*[a-zA-Z]//g' | sed -e :b -e '/^\s*$/{$d;N;bb' -e '}'
  fi
done <<<"$input"

Save it to some $PATH e.g. as kni (kiro-non-interactive) and chmod +x it, then you can execute:

kni feat1 "do A\ndo B\ndo \C"

Teh trick with $* check in code allows you to also pipe things to the script:

cat feat-a.txt | kni feat-a

Oh, and don't forget to add .kiro/workspaces to your global .gitignore!

How about git worktrees?

Glad you asked, this is another way to work on single codebase that is even cleaner than above one, if you need that.

But that's a material for another post 😄