*How I learned to work with an AI agent β OpenCode with the *big-pickle model β through a messy, real multi-repo project, and what that taught me about AGENTS.md, SKILL.md, project boundaries, and the architecture of a thought-flow.
This article is a summary of a project I actually did with an AI agent, plus the lessons that came out of it. It is not a tutorial with a happy, linear path. It is a record of practice β including the mistakes, the disagreements, and the moments where the agent was right and I was wrong, and a few where I was right and the agent was wrong. That honesty matters, because most writing about AI agents shows the polished final state, not the messy process of getting there.
The project: auto-publish SKILL.md files from three GitHub repos to ClawHub, a skill registry, using GitHub Actions β without installing any CLI tool locally, without converting any existing skills, and without breaking a bilingual publishing pipeline that already worked. It sounds simple. It was not. And that is exactly why it is worth writing down. If you want the compressed version, the Quick takeaways section at the end distills it into five rules.
How to read this.The essay is layered on purpose: theStepsare the evidence, theHighlightsandPrinciplesare the reasoning, thefailure catalogis the reference table, and theQuick takeawaysare the five rules to actually use. Each layer is a different compression of the same lessons, so you can stop at any depth.
At the time of this project, my skills and articles lived across three sub-repos under a superproject β the set has grown since:
Every sub-repo has two remotes: j3ffyang (my personal GitHub account) and negtivspace (a second personal account). Both are pushed to on every change. Everything is Linux, everything is terminal, everything is minimal.
Two accounts, one author.Both are mine:j3ffyang is my primary personal GitHub account;negtivspace ("Negative Space ηη½") is a second personal account I use to mirror the same repos. Three sub-repos Γ two accounts is where "six repos" comes from, and pushing to both is why the Step 4 double-publish race existed. And don't confusenegtivspace the GitHub account with thenegtivSpace superproject directory that holds everything.
The goal: when I push a change to a SKILL.md, a GitHub Action should detect what changed and publish the new or updated skill to ClawHub under my account β automatically, idempotently, and without me running any local tool.
Here is the part of this essay worth reading first. Over several sessions, a procedure emerged for how we share ideas and decide β sometimes with disagreement, mostly in agreement β how and when to generate AGENTS.md and SKILL.md. It is not a rigid process. It is an architecture of thought-flow, a loop that converges. Keep it in mind as you read the practice that follows β every step of the story is a working example of one of these stages.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ 1. INTENT ββ what do I want? state it plainly ββ β ββ 2. CONSTRAINTS ββ what must not change? boundaries, ββ tools, remotes, conventions, approvals ββ β ββ 3. PROPOSE ββ agent drafts a plan + options + ββ recommendation ββ β ββ 4. PRESS ββ I push back where it conflicts with ββ my constraints; we negotiate ββ β ββ 5. PRACTICE ββ approve, build, run, observe ββ (real failures live here) ββ β ββ 6. INVESTIGATE ββ when it fails, verify against the ββ real system before blaming the tool ββ β ββ 7. CODIFY ββ distill the practice into AGENTS.md ββ rules and SKILL.md steps ββ β ββ 8. BOUNDARY-CHECK ββ is this the right repo / worktree / ββ scope for this knowledge? resize if not ββ β ββ βββββββ loop ββ practice again, refine again βββββββ βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
A few notes on each stage, because the loop only works if the stages are understood:
The very first thing the agent did was not code. It was asking me to define the boundary: which repos, which remotes, which skills, which constraints. I said: publish skills from the three sub-repos, do not change any skill content, do not install anything locally, and push to both remotes as the repo rules require.
Here is the first lesson, and I will say it plainly:
The quality of the outcome depends more on how I describe the problem than on the model.
ClawHub ships an official reusable GitHub Action: openclaw/clawhub/.github/workflows/skill-publish.yml. The obvious choice was to reference it with @v1. The agent checked and found that @v1 does not exist β the latest tag at the time was @v0.23.3. So we pinned to that.
The first run failed immediately with a startup_failure:
The nested job 'publish' is requesting 'id-token: write', but is only allowed 'id-token: none'
This is a GitHub Actions quirk: a caller job that invokes a reusable workflow must declare permissions: { contents: read, id-token: write } at the job level, or the reusable workflow's own OIDC token request is denied. It is the kind of error that is meaningless until you have hit it once, and instantly recognizable forever after.
Fix one: add the job-level permission. Push. Watch it run further.
The publish needs a token. I have one account on ClawHub: j3ffyang. The agent proposed setting a clawhub_token repository secret on all six repos (three sub-repos Γ two remotes). That was the first moment of real friction: **secrets could not be set on the **negtivspace copies of two of the repos.
Why? Because negtivspace is a user account, not an organization. A user account's repo only lets the owner set secrets, and the owner is the account itself β my other account (j3ffyang) could not set secrets there without write access. GitHub's secret API needs the caller to have write permission on the repository, and collaborator-level access was not granted.
The fix was a small but real collaboration change: I granted the j3ffyang account Write collaborator access on negtivspace/ai-custom-skills and negtivspace/ai-thoughts. Then the secrets went in.
Now the workflows actually executed. The logs showed failures, but the failures split into two families, and telling them apart was the entire game:
**Family A β **Version X.Y.Z already exists. Increment the version number and try again.
astro-sync (in both history and ai-thoughts), zh-history-literature-culture (history), and blog-image-enricher, indepth-perspective, image-to-video-gen (ai-custom-skills) all failed with this. I assumed the workflow was broken. The agent was not so sure, and dug into the ClawHub CLI source (/tmp/opencode/publish-v0233.ts) to read how version resolution actually works.
The root cause was beautiful and infuriating at the same time: both remotes of every sub-repo run the same workflow, and both publish to the same ClawHub account. j3ffyang/history and negtivspace/history were racing to publish astro-sync at the same time. Whoever landed first created 1.0.0; the other got "Version 1.0.0 already exists." It was not a bug in my workflow at all. It was a double-publish race I had designed into the system by pushing to two remotes.
The agent did not just assert this. It queried the ClawHub API with the token and showed me the actual records: every βcollidedβ version existed on ClawHub under j3ffyang, with timestamps in the exact window the workflows ran. That is the practice I value most now: when something looks broken, verify against the real system before assuming the tool is wrong.
**Family B β **Invalid publish output: 'pending-publication'
This one looked like a real error too. The agent read the upstream reusable workflowβs Python, and found the truth: the workflowβs status map only recognizes would-publish, published, and unchanged. The ClawHub CLI, when a publish is submitted and awaiting an async security scan, returns pending-publication β which the upstream workflow does not map, so it throws, and reports the skill as failed.
But the skill did publish. The API confirmed blog-polish-zhcn@1.0.14, resize-for-banner@1.0.0, and the rest were all live on ClawHub. The "failure" was a cosmetic upstream status-mapping bug β a false alarm baked into the third-party workflow, not my system.
The fix for Family A was one condition, added to both jobs in all three workflow files:
if: github.event_name != 'pull_request' && github.repository_owner == 'j3ffyang'
github.repository_owner resolves at runtime from whichever repo runs the workflow. On j3ffyang/, the owner matches, and the publish job runs. On negtivspace/, the owner is negtivspace, the condition is false, and the job is skipped. The negtivspace copies keep the file β the mirrors stay in sync β but they become a no-op by design. One source publishes. The race is gone. Every run after that was green. This is the single most important engineering decision in the whole project, and it came from a small conversation: I described the symptom ("collisions"), the agent traced it to the design (two remotes), and I agreed to the fix (a guard) rather than trying to make both remotes coexist. The rule now lives in a skill, documented so neither of us forgets it.
With the race fixed, a quieter problem surfaced. Both history/.opencode/skills/astro-sync and ai-thoughts/.opencode/skills/astro-sync exist. They have the same slug but different content β the ai-thoughts version had been adapted (different source paths, no fact-checking step, a featured parameter). ClawHub treats slugs as unique per owner, so the two copies were overwriting each other on every publish. ai-thoughts had just published astro-sync@1.0.1, clobbering history's 1.0.0.
The agent proposed deleting or renaming history's copy. I pushed back: **I still need ****astro-sync in the **history project. It is the skill that publishes history articles to my blog; removing it would break my own workflow.
Here is where the agent did something right: it did not argue, and it did not just agree. It checked how OpenCode discovers skills (walks up from the current directory to the git worktree root, .opencode/skills, .claude/skills, and .agents/skills), and it proposed a compromise I had not thought of:
Nothing was lost. The local skill stayed authentic, the registry stopped getting clobbered, and my blog workflow kept working. That is the kind of outcome I want from a collaboration: not the agentβs first idea, and not mine, but a third option that respects the real constraints.
The last step was turning the messy process into durable knowledge. We created a skill, .opencode/skills/clawhub-publish/SKILL.md, that documents the whole pipeline: the single-source rule, the owner guard, the version semantics, the pending-publication false alarm, the slug-collision policy, and how to verify a publish with the ClawHub API. Our first instinct was to put it at the parent level β but a session opened inside a sub-repo cannot see a parent-level skill, so it landed in ai-thoughts/.opencode/skills/, where the publishing work actually happens. The workflow files were committed to both remotes, submodule pointers were bumped, and every j3ffyang run went green.
The whole journey took a few sessions. Nothing in it was a single brilliant move. It was a loop of intent β constraints β propose β press β practice β investigate β codify β boundary-check, run enough times that the system became boring and reliable.
Now the part I want to keep. These are the highlights, each one earned by practice β and each one reappears, compressed, in the failure catalog below.
I run OpenCode in the terminal, on Arch Linux. My default model is big-pickle β free (with condition), fast, and consistently good. This combination does not ask for a subscription, and it does not throttle me into uselessness. The big-pickle model handled a multi-repo, multi-account, external-registry automation project without drama: it read the upstream workflow source, queried the live API to verify hypotheses, and reasoned about GitHub Actions permission quirks it had clearly seen before.
The moment that changed my attitude was in Step 4, when the agent said, in effect: βlet me read the ClawHub CLI source to understand how version resolution works.β I had assumed the collisions were a config error; the agent went a level deeper, downloaded the source, and read the actual resolution logic. That is not pattern-matching β it is investigation, and it is the point: a good agent with the right tools (bash, web fetch, file reads, git) can do genuine debugging across a system I had no visibility into. My imagination was the limit, not the model.
I want to be blunt about this, because it is the most useful lesson and the least comfortable one:
When the agentβs output does not match my expectation, the fault is usually in how I spoke to the agent, not in the agent.
Every frustrating failure in this project traced back to something I had not said clearly:
The moments where I got the outcome I wanted were the moments where my instruction was precise: single-source, no content changes, no local installs, push to both remotes. Precision in, precision out. Vagueness in, guesswork out.
This is not to let the agent off the hook β it made real mistakes too, and I overrode it when I had context it lacked. But the honest accounting is that most of the misses were mine, and most of them were communication misses.
Here is the claim I care most about:
AGENTS.mdandSKILL.mdare not documentation. They are the interface between how I think and how the agent operates.
In this project, the AGENTS.md files did real work. The history/AGENTS.md tells the agent that every change needs approval, that facts need two sources, that filenames follow YYMMDD-slug. The parent negtivSpace/AGENTS.md tells it to push to both remotes and how the profile README sync works. Without them, the agent would have asked me the same questions every session, and the answers would have drifted.
The skills did real work too. astro-sync turned a long editorial procedure into one request. clawhub-publish turned a hard-won debugging session into a checklist the agent can follow next time. The effort is front-loaded β but the payoff compounds, because the knowledge survives the session.
The most subtle lesson was about where a skill or an AGENTS.md should live.
I discovered, by practice, that OpenCode discovers skills by walking up from the current directory until it reaches the git worktree root, and it does not cross into the parent superproject. Proof: I created .opencode/skills/clawhub-publish/ in the parent repo, and a session opened inside history/ could not see it at all. The skill was invisible precisely because history/ is its own git worktree.
This is the boundary problem in miniature:
The sweet spot I settled on: an AGENTS.md per git worktree (each sub-repo gets its own, plus one for the parent), and a SKILL.md only for procedures I actually run more than once. The astro-sync collision taught me the boundary the hard way: the skill had to be local to the project that uses it and published from only one repo. Same skill, two concerns, one boundary each.
I want to keep this short because it matters: the agent recommended placing clawhub-publish at the parent level, and I initially accepted β only to unwind it once we found a session inside a sub-repo cannot see a parent-level skill. It also gave me a recommendation I rejected (moving history's astro-sync to .claude/skills/, which I refused because the skill was written for OpenCode, not Claude) and a recommendation I eventually loved (the skill_path compromise).
The skill is not in following every recommendation, and not in ignoring them all. The skill is in treating the agentβs proposal as the first draft of a decision, not the decision itself. I hold the constraints (the history project still needs astro-sync; the skill must stay authentic; nothing gets installed locally; both remotes get pushed). The agent holds the system knowledge (how OpenCode loads skills, how ClawHub resolves versions, how the workflow maps statuses). The best decisions came from me stating the constraints and letting the agent find a path through them β then checking the path against my constraints before accepting it.
One small but effective habit: write the operating preferences directly into AGENTS.md so the agent never has to ask.
In my case:
- minimalist, Linux only, prefer command line- no local installs unless approved- get approval before any change- commit only when asked; stage only intended files
These are not technical instructions. They are character. And they change the behavior of every session. The agent does not propose GUI tools, does not install things without asking, does not barrel ahead on edits, and stages only what I told it to. That last one saved me repeatedly: when the parent repo had modified submodule pointers and an untracked folder I did not want touched, the rule βstage only intended filesβ meant the commit contained exactly the SKILL.md and nothing else.
I will say the obvious thing plainly: I love this tool in the terminal. The TUI is where I live β fast, keyboard-driven, no tab-switching to a web app. It runs on my Linux box, it respects my constraints, it reads my AGENTS.md files, and it keeps my workflow in git. The Tab key toggles plan/build mode, which is how this whole project worked: plan, approve, build, verify, repeat. It feels less like "using a product" and more like "hiring a very fast, very literal colleague who remembers everything I write down."
Part of the appeal is that the terminal shows its work. Every message the agent produces is printed out in front of me β the tool calls it runs, the reasoning it goes through, the thought flow and the logic it followed. I can watch the AI think, not just read its conclusions. And because I live on Linux, the error messages are mostly native system errors β No such file or directory, error: failed to push some refs, startup_failure, exit codes β which make instant sense to me. When something fails, I can see exactly what happened, no translation layer, no friendly-but-vague wrapper hiding the cause. To me, that transparency is the whole difference between trusting a tool and merely using it.
Everything above was distilled from concrete failures. It is worth keeping them as a catalog, because each one maps to a lesson and a rule I now enforce:
The pattern across every row is the same: an error message is a clue, not a conclusion. The discipline that unblocked every row was the same too β investigate against the real system (read the upstream source, call the API, check the tokenβs identity) before changing anything.
To make the playbook concrete, here is the shape of the AGENTS.md and SKILL.md files that emerged. Not as templates to copy β as evidence of the pattern.
A minimal AGENTS.md for a content repo looked like this:
Three sections. That was enough. Everything else β the profile sync, the two remotes, the publishing rules β lived either in the file that needed it or in a SKILL.md.
A SKILL.md for a repeated procedure had this shape:
---name: clawhub-publishdescription: Publish SKILL.md files to ClawHub and diagnose publish failures.---# ClawHub Skill Publish## Single-source rule - read before anything else- Only the j3ffyang/* copies publish. negtivspace/* copies are no-ops by design.## Pipeline- Workflow per repo calls the reusable workflow, pinned to a specific tag.## Status & version semantics- unchanged β nothing to do; new β 1.0.0; changed β next patch.- 'pending-publication' β actually succeeded; verify with the API.## Procedure1. Add/edit a skill in the correct root.2. Push to both remotes; the j3ffyang copy publishes.3. Wait for the run; check the summary for the slug.4. Verify on ClawHub with the API; check the latestVersion and owner.## Error Handling- Version already exists β already published; next run marks it synced.- Slug collision β only one repo publishes a given slug.
The details differ per project. The shape does not: rules at the top that must not be skipped, the pipeline as a map, status semantics so a false alarm is not treated as a breakage, and a procedure short enough to follow.
The method I ended up with is personal. I do not claim it is the right way, or the only way. There is no 100% right and wrong in this territory β no black and white. What I can say is that the approach worked for me, and that it is built on a few principles I keep returning to:
If you remember only five things from this essay:
I started this project wanting to auto-publish skills. I ended up with a small, reliable pipeline, a set of conventions that make the next project faster, and a much clearer idea of how to work with an AI agent at all. The pipeline itself is almost boring now β which is exactly what I wanted. The interesting part is the loop that produced it.
The practice that made it work was writing down what I know β in AGENTS.md for the rules, in SKILL.md for the procedures, and now in this essay for the thinking.
If you take one thing from this, let it be this: the agent is only as good as the boundary you give it, and the boundary only works if you write it down. Everything else is just practice.
btw, i use arch
AI Agent Collaboration: An OpenCode Playbook Built on AGENTS.md and SKILL.md was originally published in Dev Genius on Medium, where people are continuing the conversation by highlighting and responding to this story.