Turning an agent from doing tasks into owning a function

2026-08-26Firat Dogan

For the last few months, I’ve been experimenting with agents and the tools around them.

Previously I co-founded and ran an open source startup that grew to thousands of users and paid customers at Fortune 100 companies before it was acquired.

One lesson keeps coming back: an agent can save time on individual tasks while leaving you responsible for the whole job.

Ask it to find posts, draft a reply, or pull last week’s analytics, and each task works. You still have to start the next one, explain the context again, remember what happened last time, and decide what the agent is allowed to do.

For much of that time, I was getting work done, but I was still operating every loop myself. In my experience, that gives you less than 10% of the multiplier an agent can create.

The larger gain comes when you hand over a function.

“Manage my social media” is a function. It finds conversations worth entering, drafts in my voice, waits for approval, publishes, measures the result, and uses that evidence in the next run. It continues across days without forgetting where it stopped.

A function needs a state machine

A task has a finish line. A function returns tomorrow.

For my Social Manager, every opportunity moves through a small set of states: discovered, selected, drafted, approved, published, and measured. The state machine is simply the record of where each item is now and which step is allowed next.

If I reject an angle, it stays rejected. If I select a post, the system can draft it but cannot publish it. If I approve exact wording, the publishing plan can use that wording for the next 24 hours. Once it goes out, an analytics checkpoint becomes due after 48 hours.

I no longer need to tell the agent what to do after every step. I make the decisions that require my judgment, and the system handles the sequence around them.

Building this felt like onboarding a teammate. A teammate needs shared company rules, a clear role, repeatable workflows, a memory of what has happened, and access to the tools required for the current work.

Working directory — how the function operates

A Roster-managed repo uses several files because not every instruction has the same scope.

At the root, CONTEXT.md is the canonical context for the workspace. It contains the project identity, shared operating rules, approval boundaries, team layout, and the instruction to start the orchestrator. AGENTS.md is the entry file Codex reads, while CLAUDE.md is the entry file Claude Code reads. In my repos, both point to the same CONTEXT.md, so the two runtimes load one set of repo-wide rules instead of slowly drifting apart.

The names are easy to confuse. AGENTS.md, plural, is a runtime entry point for the whole repo. agent.md, singular, belongs to one individual agent. The Social Manager has one at gtm/social-manager/agent.md, but that file is only one layer of its definition.

The Social Manager is assembled from four pieces:

  • agent.md — the individual agent contract. It states the purpose, inputs, outputs, approval boundary, available plans, and tool-binding schema. It should change slowly, but it does not contain the step-by-step workflow.
  • config.yaml — the project-specific operating configuration. It points to the voice and channel guidelines, names the accounts and providers, and sets cadence, limits, and tool bindings.
  • plans/*.yaml — the workflow logic. Discovery, drafting, approved execution, analytics, and weekly review are separate plans with explicit inputs, outputs, steps, and approval requirements. A plan can call a smaller plan or another agent’s plan.
  • gtm/EXPERT.md — function-level judgment. I use the GTM expert for ad hoc, strategy-heavy work such as shaping messaging or improving the operating substrate. Scheduled and repeatable work belongs to the Social Manager’s plans.

That separation lets me change one operating detail without rewriting everything else. I can adjust the discovery cadence in configuration, revise the ranking steps in a plan, or improve the repo-wide approval rule in CONTEXT.md. The individual agent contract only changes when the Social Manager’s actual responsibility changes.

This is the working directory in practice: one shared context for the repo, a contract for the individual agent, configuration for this installation, plans for repeatable execution, and an expert for work that needs judgment. The current run loads the pieces it needs instead of carrying one giant prompt.

Postgres and S3 — what happened before

Instructions alone do not give the function memory.

The Social Manager needs to answer questions such as: Have we already seen this post? Which angle did I reject? Which draft did I approve? Is the 48-hour analytics snapshot due?

I keep that state in Roster Brain. Underneath, it uses Neon Postgres for clean, queryable records and S3 for the heavier evidence attached to them.

Postgres stores facts and events: a post was discovered, an angle was rejected, a draft was approved, a reply was published, a metrics snapshot was collected. It also links them, so I can move from a published reply back to its draft, source conversation, discovery run, and analytics.

S3 holds screenshots, raw provider responses, research exports, and draft variants. Postgres keeps the useful record and a pointer to the original file.

Notion has a narrower job. It is the editorial calendar for standalone posts and articles I may want to schedule, edit, or republish. Replies and comments still matter as writing and performance evidence, but they do not need to clutter that calendar.

What the corpus is

Before the agent drafts, it retrieves examples from a corpus. This is a curated library of writing evidence: my work, my edits, and selected references.

Every item records who wrote it, where it appeared, its format, topic, date, approval status, and what kind of influence it may have.

Those labels matter. Something I wrote and approved can influence voice, rhythm, phrasing, and point of view. A Paul Graham essay can help with the progression of a long argument, but it cannot supply my personal experience or make the draft sound like Paul Graham.

Retrieval has two stages. First, the system narrows the eligible material using authorship, channel, format, date, and approval status. Then it searches for meaning inside that smaller set.

Suppose I choose a LinkedIn post about agents replacing repetitive founder work. The first stage limits the search to my approved English writing, recent edits, and long-form structural references. The second finds the closest ideas, even when they use different words. The writer receives a small context packet.

Similarity alone cannot tell whether an item is mine, approved, recent, or suitable for LinkedIn. The filters decide what is eligible. Semantic search decides what is relevant.

Tools — what the function can reach

The final layer is access to the outside world.

For discovery, Bright Data collects public posts from X, LinkedIn, and Reddit. Exa finds broader context around a person, company, or topic. Zernio and Composio add connected-account context when needed.

For execution, Zernio is the first provider because it covers publishing, scheduling, media, engagement, inbox actions, and analytics. Composio is the fallback when Zernio cannot safely perform or verify an action. An authenticated browser is the final fallback.

The important part is when those tools become available.

During discovery, the agent gets read tools and no publishing capability. After I approve an exact post, reply, comment, or message, the execution plan loads the provider. If a write returns an unclear result, the system checks the platform before attempting a fallback.

This improves tool selection too. An agent choosing among forty vaguely related tools has to guess. A plan exposing four relevant tools gives the model a smaller decision.

The function has three durable layers:

  • The working directory holds shared context, the agent contract, configuration, and repeatable workflows.
  • Postgres and S3 hold state, examples, and evidence.
  • The current plan exposes the tools needed for its next action.

These three parts preserve the function when the model changes.

discover opportunities
→ save and rank them
→ ask me to select
→ retrieve writing context
→ draft
→ ask me to approve the exact copy
→ publish or schedule
→ collect the 48-hour snapshot
→ review repeated evidence

How the Social Manager runs

The discovery loop is designed to run every six hours across X, LinkedIn, and Reddit. It reads the active campaign, gathers candidates from public and connected sources, removes duplicates, and filters anything stale, weak, irrelevant, or already seen.

It aims to return 10–15 strong candidates and returns fewer when the material is weak. Each includes the post, engagement and velocity, a summary, relevant author background, why it fits, and a recommended action. That may be a reply, a standalone post, or an outbound signal.

Recommended likes, reactions, and upvotes can happen automatically. Posts, replies, comments, quote-posts, DMs, and email always stop for explicit approval.

When I select an opportunity, that decision is stored. Before writing, the drafting plan queries Roster Brain for examples matching the channel, action, topic, and length, plus recent edits where I changed the agent’s wording. It gives me two or three variants.

I can choose one, reject all, or rewrite a sentence. That becomes evidence for later drafts. Publication still requires a final packet with the target, exact copy, and separate approval.

After publication, the item enters the measurement queue. A scheduled sweep collects one normalized snapshot after 48 hours. The raw response stays in S3; useful metrics become an event linked to the published item.

Once a week, another plan reviews repeated results across topics, formats, and timing. My direct edits update voice evidence immediately. Engagement informs distribution without allowing one viral post to redefine how I write.

The human owns the decisions

My loop stops for me at named decisions: choose the opportunity and approve the exact wording. Between those points, the agent knows the next step and carries the state forward.

Babysitting happens when the human has to remember the sequence and keep answering “what next?” Here, I own judgment and the system owns the sequence.

That is the multiplier I was missing. I can hand the function a campaign and return to a ranked decision packet instead of reconstructing the process in a new chat.

The honest cost

For the first few weeks, this took more time than doing the work by hand. I could write faster myself. Connecting an API was easy. Correcting drafts, defining states, setting approval boundaries, and turning repeated corrections into durable evidence took the time.

The improvement is cumulative: every stored decision, edit, and outcome gives the next run a better starting point.

Start with one function

Pick one function you understand well enough to review closely.

Write down what it owns. Split recurring work into plans. Define the states. Put instructions in the working directory, history in Postgres, raw evidence in object storage, and tools inside the plan that needs them. Choose the few decisions that must return to you.

The same structure works elsewhere. A research function can run scans, apply source rules, and return a review queue. Sales can track account state, qualification, approved messaging, and follow-up. Product can move tickets through implementation and verification.

The value comes from continuity. A company function needs to know what happened yesterday, what it may do today, and what evidence should change tomorrow’s run.

I built Roster as the open-source state machine and workspace scaffold behind this approach. The working directory, plans, approval boundaries, and brain are designed to run with Claude Code, Codex, or another agent runtime.

Roster is open source on GitHub.