WARNING ON PROMPT INJECTION
Don’t run this example - it is for demonstration purposes only. Naively implementing this will leave you open to prompt injection attacks and will put your system at serious risk. You must carefully think through any loops you create and who can inject prompts into your system, and what damage that could cause.
Ok, health warning out the way, let’s --dangerously-skip-permissions
Prompt Engineering became Context Engineering became Harness Engineering became Loop Engineering - that’s the narrative, but it’s not right.
Context Engineering is still what we’re doing - getting the right context to the LLM at the right time. Too much, too early, can cause confusion and lack of focus. Too little, too late and you won’t end up with the result you desire. Getting the right context at the right time used to mean simply a well crafted prompt, hence Prompt Engineering, but as the things we want agents to build become more and more complex, the systems, tools and process we are using to craft this context, and submit it at the right time, are evolving.
As well as the initial prompt, we want to give the LLM richer context, such as real time data from search engines or data from other places like from documents on our local file system. More complex context crafting = Context Engineering.
A Harness enables the LLM to call tools - like querying a search engine, or
executing linux commands on the local system. Adding tools = Harness
Engineering, basically. The UX at this point is still human going from prompt to
prompt.
Loop Engineering enters the chat.
Loops represent repeatable units of work, or workflows. You can and should break
bigger complex workflows up into multiple loops that chain together. Users are
now able to identify workflows that are repeatable and automatable, and the tool
to do this is a loop, which tbf, has for a long time also been known as, a
job.
Prompt -> Result -> Prompt -> Result
becomes
Autonomous Loop(1) -> Result -> Autonomous Loop(2) -> Result
Simplified example:
Loop(1): “Review GitHub issues with label needs-triage, then remove label
needs-triage, then propose solution as new comment, then set label todo.”
Loop(2): “Review Github issues with label todo, then remove label todo,
then implement the proposed solution from the comment section, then set label
to-review.”
We want our loop to run periodically, say, every 30 minutes. How do we do this?
Antigravity Sidecars
“Sidecars are background processes that run alongside Antigravity. Antigravity manages the lifecycle of sidecars, automatically launching them and restarting them if they crash or error.” - https://antigravity.google/docs/sidecars/
Sidecar configurations are saved in
~/.gemini/config/sidecars/<name>/sidecar.json
Antigravity can run any arbitrary command, and today has one builtin which
is schedule.
The first argument of schedule is a standard 5-field cron expression.
We have a couple of options for commands we can run that will drive LLM interactions:
1 - agentapi - The CLI for Antigravity (2.0) UI - The advantage of using this
CLI is the conversations will appear in the Antigravity UI.
2 - agy - The Antigravity CLI
For the workflow I’m running, the agent needs access to gh (GitHub CLI) to
read and write to issues.
That means that this agent needs to run in a
Project - I’ll skip over the
details here for brevity - for now, the explanation is if we don’t use a project
we’ll keep getting a popup requesting user input allowing access to the gh
tool, and that doesn’t work for an autonomous loop, we want no humans in the
loop and as I don’t need to see these in the UI I’m going to use agy.
Demo Loop
For our example workflow here is the sidecar configuration:
{
"builtin": "schedule",
"restart_policy": "always",
"args": [
"*/30 * * * *",
"agy",
"--dangerously-skip-permissions",
"--project",
"loop-engineering",
"--prompt",
"Check https://github.com/paulmattei/loop-engineering-101 for open issues with the label 'needs-triage'. If no open issues have this label, exit immediately without making changes. For each issue found: assess feasibility, add a summary comment with next steps, apply appropriate tags ('bug'/'feature'/'enhancement'), and remove 'needs-triage'."
]
}
Notice how the needs-triage label acts as a queue/state cursor. This ensures
our loop is idempotent: once an issue is processed, it won’t be re-triaged on
subsequent runs.
We save this configuration at
~/.gemini/antigravity/sidecars/github-triage/sidecar.json and now Antigravity
handles the lifecycle in the background.
And we enable the sidecar in the configuration in ~/.gemini/config:
{
"sidecars": {
"github-triage": {
"enabled": true
}
}
}
Results
See the Issues I created to try this out, with the tag changes and comments the agent added: https://github.com/paulmattei/loop-engineering-101/issues