← Back to context

Comment by Syntaf

6 hours ago

I’ve been working on a harness for accounting agents at my job recently and it’s been a pretty interesting experience.

We originally started with building a CLI tool so our LLMs could more easily interact with our platform. I cannot recommend enough the value of having an internal CLI. It’s both fun to build and extremely useful for agents.

We paired this with skills initially, but found that the way folks built skills was often too prescriptive and limited to the authors own specific function in the company. A 2k line long skill suffers from the same gaps as we do, if an agent is just following a laundry list it’s less likely to reason about the request it’s doing.

So we instead asked ourselves: what if we just _let_ the agent reason about the work to be done and only provided the tools + guardrails to gather context and perform accounting work?

Turns out frontier models are GOOD at what they do, they outperformed our highly prescriptive skills and were able to work across a larger set of tasks even without instruction on how to do those tasks.

It’s a breath of fresh air from the decade of CRUD I’ve worked on, harness engineering is very neat.

I think you've really hit the mark on how the harness should be structured:

1. Guardrails - deterministic, social intelligence, team alignment & accountability 2. Learn by doing 3. make it stupid easy for the agent to research and access data 4. DRY

Research supports this. Try picking up some ideas from my harness: https://github.com/rush86999/atom

This is the same "tension" I keep seeing in my day job. Some people approach LLMs like they're writing code. They give a long list of detailed instructions for specific scenarios. When I use LLMs I leave things as open as possible. I just give them the information they need and my ask.

As you say frontier models are very good at figuring things out. Being too prescriptive is counterproductive, it over-constrains the model, it fills the context with conflicting instructions, it reduces the ability of the agent to respond to novel situations (and really in real life most situations are going to be novel). If you want to follow a process or a checklist you probably shouldn't use an LLM, or you should use it for some sub-tasks in the checklist/process but something more deterministic to work through the list.

  • > When I use LLMs I leave things as open as possible. I just give them the information they need and my ask.

    How do you handle security?

    Both “internally” against e.g. data loss, I’m assuming via limiting the harness, and “externally”, i.e. stuff like prompt injection risks?

  • That works for well trod paths, e.g “fix ci” works exceedingly well. “why app slow” obviously doesn’t work because the task is underspecified. But in order to properly specify you either need an experienced engineer who knows how to narrow the problem domain, or you have to provide some template instructions/output formats (e.g, skills) which will invariably never fit the problem perfectly

    • > . “why app slow” obviously doesn’t work because the task is underspecified.

      Not always. In my case LLM goes to grafana mcp, pulls metrics/traces/cpu profiles. Figures out what is slow and proposes a solution.

    • I wouldn't agree. Sota models can do self-directed sampling, profiling, benchmarking, read call trees, etc. to give you a report of the app's bottlenecks and then recommend solutions that can be vetted.

      I do this constantly.

      As the upstream comment points you, you don't need to specify. Sota models are that good. And by being overprescriptive you can accidentally shut off branches that they would've taken, downgrading the quality of their work.

      2 replies →

    • I use skills. The skills are not typically "how to perform a task in detail" they are more about what relevant tools and knowledge are required to work in a domain. That is I give the LLM the information it needs about the system but not a sequence of how to accomplish a task. I treat it more like a human and less like a computer.

    • It really doesn’t need to be that much more specified, give it context to the tools and level of analysis you expect then “why app slow” is a reasonable prompt

I've been building a harness (on top of Pi for that matter) and have had similar experiences. Pi itself helps a lot with it being extensible by design but it's definitely been a challenge to make certain things work in an expected way.

The native app I'm building on top, which I hope people who are less technical (or not technical at all) will use, is even more interesting because it's not just supposed to shell out to the CLI for everything and needs its own state.

Can you post a generic version of code for this somewhere (e.g. codeberg or whatever)?

I find your description intriguing but I'd like to see it to make sure I understand it.

  • Sorry I can't share what we're doing here directly!

    I will however say that this page alone does a pretty good job of illustrating what an agent harness might look like: https://docs.agno.com/tools/overview

    * System prompt

    * Tool calls

    * Model definition

    Everything else (guards / etc) can just exist as code abstractions between the agent layer and the tool layer.

So you still have CLIs but they have I presume an help command that describes the capabilities right.

Could you give an example of an accounting guardrail you created?

  • I’ve also found that Claude and friends are eerily good at using classic Unix CLI tools so I build mine in the same style, not unlike the `gh` CLI from GitHub, though with an agent-first design shape.

    Usually I’m returning TSV as a default format and I add a `help-all` subcommand to list every available command at once when needed. Another thing that helps is adding just-in-time context-sensitive hints, such as: user has just run a list query with at least one result. Add a one-liner to the response explaining the command shape for getting the detail view of the first response.

    In terms of skill files, I like to have my CLI generate them dynamically at runtime by walking their own current command tree and then feeding that through a text template.

    Examples from a public project: https://github.com/radiusmethod/gitlab-kiosk/blob/main/skill...

  • Yeah the CLI can provide schema for commands via the usual ‘—help’ syntax, so agents are able to discover + explore commands on their own.

    As for an example: if our agent wants to book a journal entry to cash accounts for a client, it MUST provide receipt and directly link the transaction from the clients bank feed, if it attempts to do so without the requisite information we deny the tool call and ask the agent to escalate back to the client for proof of receipt.

    Often times this results in the agent not doing the work and instead sending a message back to the client asking for proof of the transaction.

    For humans on our platform there may be valid situations where we’d want to allow this, but for our agent this is a hard guardrail thus why it’s not just standard validation for any JE posting on our platform.

    •   if our agent wants to book a journal entry to cash accounts for a client, it MUST provide receipt and directly link the transaction from the clients bank feed
      

      And that rule is encoded in the CLI?

      1 reply →