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