Introduction

It occurred to me that the combination of human operator + AI programming agents forms a system that, if you squint, looks like a computing system.

From there, it took me quite a few months to fully verbalize this question: are there fundamental results from theoretical computer science that could teach us something about the properties or constraints of agent-driven programming workflows?

While I am not a theoretical computer scientist myself, through my PhD thesis work—many years ago—I was happy to deeply study a sizeable bibliography of results from the foundations of computing in the 20th century. Occasionally, this theoretical foundation pokes through my current areas of work and prompts me to explore a side quest. This is one of those days.

What follows is a theoretical exploration: if we can model accurately what a human operator + AI agent do in a particular way, then certain results from theoretical science are likely to apply. I explore a few of these below.

As a practitioner, I know from experience how easy it is to dismiss theory work: practice and experience often later show that theoretical results don’t apply the way we thought they did! Which in turn means that the model wasn’t accurate, and that falsification can teach us something, etc. In our current world and economy, practical results and pragmatism reign.

However, it is also the case that we have long known about certain limits of computational theory where neither practice nor experience has yet delivered us a way to work around the theoretical limits. For example, the Halting problem is a theoretical result for Turing machines (TMs—also a theoretical idea), and yet we do not really know how to practically and experimentally solve the halting problem for the computers we’ve built in the real world. So much so that we even frequently structure our computers and software to avoid having to solve the halting problem with them (e.g. eBPF, HLSL etc).

Which is to mean: despite our possible reservations about the shortcomings of theory work that say “you can’t do this”, history did show us—at least in some domains—that fundamental results can teach us to avoid wasting time chasing wild geese. Maybe this investigation can be like that.

Additionally, again, I am not a computer theoretist. This means that I am unable to formalize the ideas that follow to the degree that theoretical rigor commonly requires. Consider thus the “results” that follow as a sketch, and take them with a pinch of salt. I would be happy to learn from experts the areas where more precise formalization would defeat the intuition I’ve shared here.

I. A More Precise Computational Model

Let me try to define something rigorous enough to reason about:

Definition: Human-Agent Computation System (HACS)

A HACS is a tuple \((A, H, W, \Sigma, \delta)\) where:

  • \(A\) = Agent
    • Input: bounded context window \(c \in \Sigma^{\leq k}\) (for fixed \(k\))
    • Output: action \(a \in \mathcal{A}\) (write to workspace, query human, halt)
  • \(H\) = Human oracle
    • Function \(H: \Sigma^* \rightarrow \Sigma^*\) (possibly partial, possibly stochastic)
    • Latency \(\tau_H\) per invocation
  • \(W\) = Workspace (unbounded tape)
    • \(W \in \Sigma^*\)
  • \(\delta\) = Context formation function
    • \(\delta: W \times \text{History} \rightarrow \Sigma^{\leq k}\) (what the agent “sees”)

One computational step:

1. Form context: c = δ(W, history)
2. Compute action: a = A(c)         [time: τ_A]
3. Execute action:
   - If a = write(σ, pos): W[pos] := σ
   - If a = query(q): receive H(q)  [time: τ_H]
   - If a = halt(output): terminate
4. Append to history
5. Goto 1

I feel this is now precise enough to ask complexity questions about.

II. Time Complexity: The Step Cost

The Fundamental Difference from Classical Turing Machines (TMs)

In classical complexity theory, we count steps and treat them as unit cost.

In HACS:

Operation Time Cost Notes
Agent inference \(\tau_A\) ~seconds, depends on model size
Workspace read \(\tau_R\) ~milliseconds (file I/O)
Workspace write \(\tau_W\) ~milliseconds
Human query \(\tau_H\) ~minutes to hours
External tool \(\tau_T\) variable, possibly unbounded

This creates a natural cost hierarchy: \(\tau_R < \tau_W \ll \tau_A \ll \tau_H\)

Implication 1: Human Queries Are Precious

If we’re minimizing wall-clock time, we want to minimize \(\sum_i 1\times[\text{step } i \text{ queries human}]\)

This connects to query complexity in computational learning theory:

  • How many queries to an oracle are needed to solve a problem?
  • PAC learning bounds, membership query complexity

Concrete result that transfers: In many learning settings, there are lower bounds of \(\Omega(\log n)\) or \(\Omega(n)\) queries. This suggests some tasks fundamentally require multiple human interactions; you can’t engineer around it.

Implication 2: Amortization Becomes Critical

If \(\tau_A\) is significant (seconds per step), then a task requiring \(n\) serial steps takes at least \(n \cdot \tau_A\) time.

But: The agent can sometimes do \(O(1)\) steps that accomplish \(O(n)\) “logical operations” (e.g., asking the workspace to run a compiler, database query, or external computation).

This is analogous to:

The agent’s “step count” is like “circuit depth”, while the work done per step is like “circuit width”.

Implication 3: Parallelism Within Bounded Depth

Some agent architectures allow parallel tool calls within one step. If we can execute \(p\) parallel operations:

\(T_{\text{parallel}}(n) = \frac{T_{\text{sequential}}(n)}{p} + \text{coordination overhead}\)

This connects to NC complexity (Nick’s Class) problems solvable in polylogarithmic depth with polynomial processors.

Question: Are there tasks that are “in P” (polynomial steps) but not “in NC” for HACS? I.e., tasks that fundamentally resist parallelization even with unlimited tool parallelism?

Plausibly yes: tasks with sequential dependencies in reasoning (each step requires the output of the previous) seem analogous to P-complete problems like Circuit Value Problem.

III. Space Complexity: The Memory Hierarchy

The Two-Level Memory Model

┌─────────────────────────────────────────────┐
│           CONTEXT WINDOW (size k)           │
│         ┌───────────────────────┐           │
│         │ "Fast" memory         │           │
│         │ O(1) access time      │           │
│         │ Bounded: |c| ≤ k      │           │
│         └───────────────────────┘           │
│                    ↑↓ δ (context formation) │
│         ┌───────────────────────┐           │
│         │ WORKSPACE             │           │
│         │ "Slow" memory         │           │
│         │ O(?) access time      │           │
│         │ Unbounded             │           │
│         └───────────────────────┘           │
└─────────────────────────────────────────────┘

This is analogous to the External Memory Model (Aggarwal & Vitter, 1988):

  • Fast memory of size \(M\) (context window, size \(k\))
  • Slow memory of unbounded size (workspace)
  • Block transfers of size \(B\) (how much we can read/write per step)

Key Results That Transfer

1. Sorting Lower Bound

In the external memory model, sorting \(N\) items requires:

\(\Theta\left(\frac{N}{B} \log_{M/B} \frac{N}{B}\right) \text{ I/O operations}\)

HACS interpretation: If the agent needs to “sort” or systematically process \(N\) items that don’t fit in context, there’s a lower bound on how many steps it takes. If this model is accurate, we can’t lower this cost: the bound is information-theoretic.

2. Graph Connectivity

Determining if a graph is connected requires:

\(\Omega\left(\frac{E}{B} \cdot \log_{M/B} \frac{V}{B}\right) \text{ I/O operations}\)

HACS interpretation: Analyzing large interconnected systems (codebases, dependency graphs) can have fundamental step-count lower bounds.

3. The “Forgetting Problem”

If \(k\) is fixed and the workspace grows without bound, the agent faces a fundamental problem: it can write information it can never again hold entirely in context.

This connects to streaming algorithms and space-bounded computation:

  • Some statistics (median, distinct count) require \(\Omega(n)\) space to compute exactly
  • Approximate algorithms (sketching) trade accuracy for space

HACS implication: Agents may need to lossy compress their knowledge of the workspace, accepting approximation.

IV. The Halting Problem

Classical Halting Problem

For TMs: Given \((M, x)\), does \(M\) halt on \(x\)? Undecidable.

Variations on the theme of undecidability

  • Level 1: The agent’s code execution - When the agent runs code in the workspace, determining if that code halts is undecidable. The agent cannot reliably know if subprocess.run(user_code) will finish.
  • Level 2: The agent’s own behavior - Given a task description \(T\) and initial workspace \(W_0\), does the agent-loop halt? Also undecidable, by reduction from the standard halting problem.
  • Level 3: The human-included system - Does the full HACS halt on task \(T\)? This depends on \(H\) (the human), which is:
    • Not even computable in the formal sense
    • Subject to external factors (human gets bored, dies, changes mind)

These points make it interesting to ask: “can we ever make an AI agent sufficiently clever that it can work on a specification and that we can always expect it to finish the task on its own?” If the answer is “no” (likely), what will be the shape of the boundary between what is doable and what isn’t?

Rice’s Theorem Applies

Rice’s Theorem: Any non-trivial semantic property of programs is undecidable.

HACS interpretation: The agent cannot reliably determine:

  • “Will this code change do what the user wants?” (semantic)
  • “Is this codebase bug-free?” (semantic)
  • “Does this refactoring preserve behavior?” (semantic)

This is a limitation of computation itself, not just the limits of current LLMs.

What the Human Oracle Buys Us

If \(H\) is an oracle for the halting problem (i.e., human can always correctly judge “is this done?”), then HACS can compute functions in \(0'\) (Turing jump of the computable functions).

But humans aren’t halting oracles. We’re more like:

  • Bounded oracles: Can only answer queries up to some complexity
  • Noisy oracles: Sometimes wrong
  • Strategic oracles: May have different objectives than the agent

This suggests modeling with:

  • Approximate oracle machines (studied in computability theory)
  • Interactive proofs with bounded provers

V. Interactive Proofs and Verification

Context: the IP = PSPACE Theorem

Setup:

  • Prover (unbounded computation)
  • Verifier (polynomial time, randomized)
  • Multi-round interaction

Result: Any language in PSPACE can be verified through interaction.

HACS as Interactive Proof

Consider the agent as prover, human as verifier:

IP Component HACS Component
Prover Agent
Verifier Human (bounded time/attention)
Transcript Conversation history
Soundness “Agent can’t fool human into accepting bad work”
Completeness “Good work will be accepted”

Something we already had an intuition about: the human doesn’t need to understand how the agent solved the problem, they only need to verify the solution. Verification can be easier than solving.

What HACS Can “Prove” to Humans

For which task classes can the agent convince a bounded human that the work is correct?

Easy to verify:

  • Code that passes tests (human runs tests)
  • Proofs in formal systems (human checks with proof assistant)
  • Factual claims (human can spot-check)

Hard to verify:

  • “This is the best solution” (optimization without certificate)
  • “This code has no bugs” (requires exhaustive reasoning)
  • “This is creative” (subjective, no formal criterion)

The verification asymmetry explains a lot about where agents succeed and fail.

Note

For complex reasoning tasks, humans still currently outperform LLMs (when they direct their attention to the problem and pay attention). This might suggest the analogy with the IP theorem is taken backwards. However, the asymmetry we’re considering here is for the case of programming assistance, where typically the AI agent produces large amounts of code that the human wouldn’t consider producing themselves, but where the human still agrees to spend some limited amount of time for verification, and succeeds in verification.

VI. Communication Complexity

A Question

How many bits must be exchanged between agent and human to solve task \(T\)?

Lower Bounds Mean Fundamental Limits

Classic result (Set Disjointness): Determining if Alice’s set and Bob’s set are disjoint requires \(\Omega(n)\) bits of communication.

HACS interpretation: If a task requires the human to convey \(n\) bits of implicit requirements, there’s no way around substantial interaction. “Just understand what I want” has information-theoretic limits.

Implications for Agent Design

  1. Specification complexity - If a task has Kolmogorov complexity \(K(T) = n\), the human must somehow convey those \(n\) bits. You can’t compress the requirements below their intrinsic complexity.
  2. Iterative refinement is sometimes optimal - Rather than one long specification, iterative refinement might be communication-optimal for tasks where the human can evaluate intermediate outputs. This is like binary search over the space of intended outputs.
  3. Shared context reduces communication - If agent and human share a “prior” (common knowledge, conventions), the communication needed drops. This is why domain-specific agents can be more efficient: they share more prior with expert users. Conversely, trying to orient users towards more “general-purpose” LLMs may increase the communication costs to get anything done.

VII. Synthesis: A Complexity-Theoretic View of HACS Capabilities

Let me try to put this together into something like a “complexity class” hierarchy for HACS:

┌──────────────────────────────────────────────────────────────┐
│                    HACS CAPABILITY LEVELS                    │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  Level 0: CONTEXT-BOUNDED                                    │
│  ─────────────────────────                                   │
│  Tasks solvable in single pass, input fits in context        │
│  Analogous to: O(k) space, O(1) "depth"                      │
│  Example: "Explain this function" (function fits in context) │
│                                                              │
│  Level 1: WORKSPACE-BOUNDED                                  │
│  ─────────────────────────                                   │
│  Tasks requiring workspace but not human interaction         │
│  Analogous to: PSPACE (polynomial human-free steps)          │
│  Example: "Refactor this codebase" (with clear spec)         │
│                                                              │
│  Level 2: HUMAN-INTERACTIVE (Bounded Queries)                │
│  ─────────────────────────────────────────                   │
│  Tasks requiring k human queries for fixed k                 │
│  Analogous to: Σ_k^P (polynomial hierarchy)                  │
│  Example: "Build X with N rounds of feedback"                │
│                                                              │
│  Level 3: HUMAN-INTERACTIVE (Unbounded)                      │
│  ───────────────────────────────────────                     │
│  Tasks requiring arbitrary human interaction                 │
│  Analogous to: IP = PSPACE (interactive proofs)              │
│  Example: Open-ended collaboration                           │
│                                                              │
│  Level ∞: HUMAN-EQUIVALENT                                   │
│  ─────────────────────────                                   │
│  Tasks where human does most of the "real" work              │
│  Analogous to: Oracle for the halting problem                │
│  Example: "Tell me what to code and I'll code it"            │
│                                                              │
└──────────────────────────────────────────────────────────────┘

VIII. Open Questions

  1. Is there a natural analog of NP-completeness for HACS? What would a “reduction” between tasks look like?
  2. How do we formalize “human attention cost”? It’s not just bits: some queries are cognitively cheap, others expensive.
  3. What’s the right model for human unreliability? Noisy oracle? Byzantine adversary? Something in between?
  4. Does the agent’s internal architecture matter for complexity? Chain-of-thought vs. direct answering seems like depth vs. width, but is this formal?
  5. Can we prove separation results? “Task X requires human interaction” or “Task Y cannot be solved with bounded context”?

IX. Other things to look at

Some directions that I’m curious about but haven’t had a chance to investigate yet:

  • The book Human Computation by Law and von Ahn. We can maybe use its models for the human participant in the HACS system. What would that teach us?
  • What would falsify the ideas explored above? What experiments could we reasonably run that would test the above and show where the model is definitely incorrect?
  • We’ve simplified the situation greatly by assuming that the agent (A) is fixed for a given interaction. However, more and more agent providers are trying to make the inference learn dynamically during the interaction. How does this impact this exploration?
  • What about multi-agent systems? In the simple case where multiple agents are organized as a tree (delegation) we are still looking at the same theoretical model, but when two agents do work separately from each other, with a human to check their work, they can prove strictly more things than just one (MIP = NEXP).

References

Like this post? Share on: BlueSkyTwitterHNRedditLinkedInEmail


Raphael Poss Avatar Raphael Poss is an entrepreneur who occasionally publishes field notes on systems, leadership, and the messy edge between technology and people.
Comments

Interested to discuss? Leave your comments below.


Keep Reading


Reading Time

~11 min read

Published

Towards a theory of agent-assisted programming

Category

Computer Science

Tags

Stay in Touch