Hi, I'm Nick Blokhin
Software architect with 20+ years in production systems.
I ship real products with AI — and show what actually works.
Nick Blokhin
Home/ Notes / Agents in the Background: No LangGraph, No LangChain Required

Agents in the Background: No LangGraph, No LangChain Required

2026.08.15

Someone recently asked me how I set up agents to run in the background — watching a folder, polling a website — and whether I use a framework like LangGraph or LangChain for it.

Short answer: no, neither. My setup is considerably more boring than that, and I think that is exactly why it keeps running for years instead of until the next major version of a framework.

Three moving parts

Everything I have running in the background comes down to three independent pieces.

The agent is a long-lived process on one of my local machines or servers. It does not monitor anything on its own — it knows how to accept a task and carry it out with its tools. Which agent barely matters here: Claude Code in headless mode, Hermes, your own loop over the API, something else entirely. For this scenario any of them will do.

The triggers are ordinary scripts and scheduled jobs. One watches a folder and fires when a new file appears; another polls a site or an API on a schedule and compares the response against the last one it saw. Nothing about this is AI-specific — it is cron and file watchers, tools that have been around for decades.

The handoff is what happens when a trigger catches something: it sends the agent a task describing what happened and what to work on. From there the agent decides which of its tools to use. You can build the handoff any number of ways — a file dropped into a queue directory, a CLI call with a prompt, an HTTP request — and the choice comes down to what is convenient for you and what kind of system you are building.

The property that makes this work: intelligence is only needed in the third part. Noticing that a file appeared, or that a page changed, is a job Unix solves without spending a single token. Paying for LLM calls — or burning local GPU cycles — so that the agent can poll the world itself is the most expensive way ever devised to write while true; do sleep 60; done.

What it looks like in practice

The skeleton of a folder trigger is a few lines:

#!/usr/bin/env bash
# Watch the inbox folder, hand each new file to the agent
fswatch -0 --event Created ~/agent-inbox | while read -d '' file; do
  send-task "New file dropped: $file. Process it."
done

Bash is not the point — the shape is. The same trigger in Python, when you want more structure and somewhere to put error handling:

#!/usr/bin/env python3
"""Watch the inbox folder, hand each new file to the agent."""
import time
from pathlib import Path

INBOX = Path.home() / "agent-inbox"

def main():
    seen = set(INBOX.iterdir())
    while True:
        current = set(INBOX.iterdir())
        for path in current - seen:
            send_task(f"New file dropped: {path}. Process it.")
        seen = current
        time.sleep(5)

if __name__ == "__main__":
    main()

Watching a website is a cron line plus a comparison against the last snapshot:

*/15 * * * * check-page.py https://example.com/releases
#!/usr/bin/env python3
"""Poll a URL, notify the agent when it changes. Run from cron."""
import hashlib
import sys
import urllib.request
from pathlib import Path

STATE = Path("/tmp/page.hash")

def main(url):
    body = urllib.request.urlopen(url, timeout=30).read()
    new = hashlib.sha256(body).hexdigest()
    old = STATE.read_text().strip() if STATE.exists() else None
    if new != old:
        STATE.write_text(new)
        send_task(f"Page {url} changed. Check what's new and summarize.")

if __name__ == "__main__":
    main(sys.argv[1])

Either language gives you the same three parts, and neither version contains a single AI-specific line. Python mostly buys you a comfortable place for the logic to grow into: retries, HTML parsing when hashing the whole page turns out to be too blunt, a filter deciding which changes are even worth an agent's time.

send-task / send_task stands in for the handoff. The point of keeping it a separate thing is that every piece can then be exercised on its own: run the trigger by hand and see what it catches, feed the agent a task directly and see what it does. When something breaks at three in the morning, there are only three places it can be.

Why not LangGraph or LangChain

I hold no ideological position that frameworks are evil. They simply solve a different problem than the one being asked about.

LangGraph and LangChain are about orchestration inside the agent process: graphs of steps, branching, state carried between nodes. "Run an agent in the background and react to events" is a question about the infrastructure around the agent — and for that the operating system already ships everything required: cron, systemd, file watchers, pipes. Those tools are older than most readers of this note, they do not get breaking changes every quarter, and their behavior does not depend on the version of a Python package.

Pulling in a framework to watch a folder means inserting a layer of dependencies between the event and the agent that adds nothing except surface area for failure. If one of my background jobs ever needs a genuine multi-step graph with branching and rollbacks, I will revisit the choice. So far none of them has.

A background agent is an unsupervised agent

One consequence goes past the original question, but leaving it out would be dishonest: an agent running in the background is by definition an agent nobody is watching. There is no "I'll look at the diff before it applies" — the event arrived at night and the agent worked at night.

Which puts the full weight on the principle I wrote about in the note on Auto Mode: boundaries have to be mechanical, not statistical. A background agent of mine gets exactly the access its class of tasks requires — its own folder, its own restricted credentials, and no direct path to anything I cannot afford to lose. That isolation can be a separate system user or a container, or you can move the whole thing onto a separate machine.

It is the same approach as in my work with coding agents: trust is configured by architecture — by what the agent can physically reach — not by a confirmation dialog.

The bottom line

The answer to the original question fits on one line: a long-lived process plus ordinary trigger scripts, zero frameworks. The event-driven half is a problem Unix solved decades ago, and intelligence is only needed once the event has been caught and has to be dealt with. The part of a background agent that genuinely deserves attention is not orchestration but boundaries — with no human in the loop, they have to be mechanical.

How I divide work with agents in general, and what I run them on, is on the AI page.