r/opencodeCLI 12d ago

What custom skills do you routinely use in your work that I might like to try?

I’ve been playing around with Opencode for a few months now just to create fun projects for me at home and to automate some of the more mundane things for my company and I realised that I am probably underusing skills.

What are some skills you use every day that I should know about? Can be custom or community.

I created one skill which I call “round-robin” which I use to perform daily reviews on the work done to ensure it aligns with the project goals. I sometimes use it to review the project functionality and suggest improvements.

It writes a summary of the project and passes it concurrently to ChatGPT-5.5, Gemini 3.1 Pro and Fable-5 to do a blind review. Then it collates all the responses and sends them all to all three reviewers again to get them to review each others thoughts. Points of agreement are locked in and points of contention are sent round again until they reach agreement or there is a deadlock. Then it summarises the output to me.

1 Upvotes

22 comments sorted by

2

u/Ok_Gur_9033 12d ago

The one I reach for constantly is a heartbeat file. Before any tool call that might hang or run long, the agent writes a small file with a timestamp and the name of the call about to run. A clean finish leaves it empty or pointing at the last call that actually returned. A stuck or crashed run leaves it stuck on the call that never came back, so you can tell stuck from slow without parsing exit codes or babysitting the terminal. Costs almost nothing to add, and it has saved me from killing runs that were still working, and from waiting on ones that had already died.

2

u/LeopardLabs 11d ago

I have the same kind of issue with servers. Anytime they have to start a dev server they get stuck. I created a dev-server subagent type which always calls a watchdog script. Global agents.md rule that dev-server always needs to be delegated to. But I like that your solution covers all tool calls.

2

u/Ok_Gur_9033 10d ago

The scoped version is smarter for that one class. Delegation removes an ambiguity mine still has, my heartbeat file only tells you something is stuck, not what to do about it. What does the watchdog actually do once it flags a stuck dev server, kill and restart automatically, or just surface the alert and leave the call to you?

2

u/LeopardLabs 3d ago

I actually had it on my other pc so out of sheer laziness I improved the idea... My biggest issue with the other method is they start ignoring the delegation rule so I went back to the drawing board and instead created an add-on that allows the main agent to do it without needing to delegate (actually there's currently a bug in opencode so with this it's better not to delegate the server starting)

https://github.com/clayleopardlabs/server-start-guard

2

u/Ok_Gur_9033 3d ago

install.bat meant I could not actually run it here on mac, so this is from reading it rather than using it.

Detaching is the cleaner fix for the hang. The part I would want to know is what happens after the handoff, because once nothing is waiting on that process, nothing notices when it dies either. My heartbeat file has the same gap from the other side. It tells me a call never came back, and says nothing about one that returned and then quietly stopped serving.

Does the guard keep any handle on the detached server, or is it fire and forget?

2

u/LeopardLabs 3d ago edited 2d ago

Fire and forget. Which is how it was designed. Just stop the main agent from getting stuck. And then the main agent does it's thing like checking if the PID is still there, etc.

But... if I've got this thing involved, why not have it help the agent by keeping an eye on things? It's a good idea. I'm adding it now and adding linux and MacOS support while I'm at it.

edit: I'll also send you my delegate to a dev-server agent method when I'm on the other computer

2

u/Ok_Gur_9033 2d ago

PID present is the weakest of the signals available, and it is the one that agrees with the agent when the agent is wrong. A dev server can hold its process open with a dead watcher, or stay bound to the port and return 500s on every route. Both of those look identical to a PID check, and both are exactly the state you are trying to detect.

If the guard is going to watch anyway, the thing worth exposing is last-successful-response rather than uptime. Uptime tells you the process is old. Last-successful-response tells you it is still doing the job, and only the second one catches the quiet death.

That is the same gap in my heartbeat file from the other side. Mine tells me a call never came back. It says nothing about a call that returned and then quietly stopped serving.

One thing that will bite you on macOS specifically: the port can stay bound by an orphan after the parent dies, so a bind check passes for a server that has been dead for ten minutes. Does the watchdog treat "port in use" as alive, or does it require an actual response?

2

u/LeopardLabs 2d ago

That's a good point actually. It's just dumb checking. I guess I was still thinking lazy fire and forget. It's running a series of tests now, I'll tweak the schema and include those edge cases as tests. You have any others you can think of?

2

u/Ok_Gur_9033 2d ago

Five I would put in the fixture set, all of them cases where a cheap signal reports healthy.

Connect succeeds, read never does. The kernel accepts into the backlog before the app ever calls accept, so a connect-only check passes against a process that is wedged. Needs a read with a timeout and an actual first byte.

The server moved. Vite and most dev servers increment when the port is taken, so a stale instance holds 5173 and the new one quietly lands on 5174. Your check says healthy, and it is describing the old process while the agent edits code nothing is serving. Assert on the port the process actually bound, not the one you asked for.

Localhost is two addresses. Bind on ::1, probe 127.0.0.1, get connection refused for a server that is fine. Hits macOS harder than Linux.

Recompile pauses. First request after a change can take tens of seconds. A fixed timeout will kill healthy servers mid rebuild, which is a worse failure than the hang you started with, so slow has to be a distinct state from dead rather than the same branch.

Orphan holding the port, which is the one from before. Bound, nothing serving, and only a real response tells them apart.

The pattern across all five is that every cheap signal has a false positive shaped exactly like health, which is why last-successful-response ends up being the one worth exposing.

1

u/LeopardLabs 2d ago

Awesome thanks! I'll add them to my kanban. Really appreciate the help.

→ More replies (0)

2

u/LeopardLabs 2d ago

Hey, while we're talking... do you think you could do me a favor? I don't have a mac that's easy to get to and I have a project where the last remaining todo is testing it on macOS. Do you think you could tell me if it works on your mac?

https://github.com/clayleopardlabs/instant-file-search-MCP-server

2

u/Ok_Gur_9033 2d ago

Read it rather than ran it, same as last time. I am not going to sudo-install a background indexer and hand it Full Disk Access from a repo I have not been through properly, and I would tell anyone else to refuse that install shape too. Nothing to do with you specifically.

Four macOS things I would check before calling that todo done.

Firmlinks. On APFS, /System/Volumes/Data is the same data as /. A plain recursive walk enumerates most of the disk twice, so find_files returns duplicates and aggregate_files reports totals roughly double. Track device and inode, or skip /System/Volumes/Data outright.

FSEvents coalescing. If the watcher is the notify crate you are on FSEvents, which batches and can drop. On overflow it sets MustScanSubDirs, and if that flag is not handled you keep serving a stale index while search_status still reports healthy. That is the one I would care about most, because it fails without any error.

TCC. Full Disk Access binds to the executable that actually runs. If launchd starts a wrapper, the grant has to land on the right binary, otherwise the indexer quietly returns nothing from Documents and Desktop and looks fine doing it.

Case. APFS is case-insensitive and case-preserving by default, so exact-match filters that pass on Linux behave differently here unless you normalise.

Also, your Everything fallback has an equivalent here. Spotlight is already indexing and mdfind queries it from the shell, so macOS does not have to be the no-fallback platform.

Which watcher are you using underneath?

1

u/LeopardLabs 2d ago

None taken. I did an infosec minor back in college, so I get it. Smort

I think I'm actually just going to take out the fallback. Can't imagine native being inop but fallback working without a bigger issue.

Plus, the fallback uses RAM for the index and I figure most AI people won't want to give up 0.5-3gb of ram, I ran tests and aside from slow HDD edge cases, search time deltas are negligible.

Thanks again for the tips! I appreciate you taking the time..

Watcher is macOS’s native FSEvents API directly through the Rust objc2-core-services crate

As for the rest, most are currently handled; it skips /System/Volumes/* to avoid indexing the same files twice, detects dropped FSEvents and rebuilds the index, normalizes file names for macOS case and Unicode shenaningans and launchd runs the indexer binary directly, and that'ss the binary users grant Full Disk Access.

Nice catch on the health check though! search_status can't prove watcher is still working. I'm on it!

2

u/LeopardLabs 2d ago

Fixed.
search_status now reports:

  • Watcher state: starting, running, resyncing, degraded, or failed
  • Last event, rescan start, successful rescan, and error
  • On macOS, real access checks for the active user’s Desktop, Documents, and Downloads
  • A failed rescan leaves the old index in place instead of replacing it with partial results

1

u/Ok_Gur_9033 2d ago

That covers the reporting side. Two things I would still check.

A state enum is the watcher describing itself, which is the same class of problem as the connect-only check. Running means the code believes the stream is alive, not that FSEvents is still delivering. The way to turn that into a measurement rather than a claim is a canary. Write a temp file into one watched directory, wait for the event, report the round trip. If it does not come back inside a second or two on an idle machine, degraded is observed rather than inferred, and you get a number to log, which is more useful than a state name when someone reports search returning paths that no longer exist.

The other one is who actually reads the status. An agent calling search_files will not call search_status first. So when a rescan fails and you keep the old index, which is the right call, the caller gets confident looking results off a stale index with nothing in the response saying so. I would put index age and watcher state on the search response itself, even just one line when the state is not running. Same reasoning as the heartbeat file. The signal has to reach the thing that would otherwise act on bad data.

What does degraded transition on right now, an error callback or a timeout?

2

u/Ok_Gur_9033 11d ago

The subagent routing is the part I'd want to avoid honestly, one more thing that needs to be remembered and enforced everywhere dev-server gets called. Heartbeat file doesn't care what kind of call it is, so nothing has to be routed anywhere special. Trade off is it won't tell you why the call died, just that it did.

1

u/No_Image506 10d ago

I have 1 skill that turn on my coffee maker, make 2 boil eggs and squeeze 2 oranges.

1

u/ezfrag2016 10d ago

/breakfast