A dotfiles-inspired portable setup for agent configs, skills, hooks. Features a model-agnostic filesystem memory layer to prevent vendor lock-in and support for 24x7 agent execution in a remote workspace.
The TL;DR
Before we dive in, you can just use this prompt with your favorite agent to re-use the best parts of the setup that are relevant for you:
Read through https://github.com/ma08/botfiles/ and grill me (like the skill in that repo) on what parts I should incorporate into my own setup.
Overview and my main learnings:
Survival requires optionality: The agent ecosystem is dangerously volatile. As I explored recently in The Autonomy Paradox article, if your workflows are locked into a single model family stack, you are vulnerable. Building a system that lets you swap models easily is a necessity.
The "Botfiles" pattern solves the context problem: By maintaining global instructions (AGENTS.md/CLAUDE.md), reusable skills, and hooks in a dedicated repo and a filesystem-backed memory layer, you can easily pause a task in one agent and seamlessly resume it in another. The human-friendly nature of a filesystem memory is an added advantage.
Full autonomy is a myth (for now): The hardest part of agentic engineering is avoiding human context-switching burnout and not getting lost in maintaining the autonomy machine. Creating and maintaining the setup can easily consume all the time meant for actual work. You need abstractions that maximize your attention without turning you into a full-time babysitter for your own tools.
Remote workspace for 24x7 Agents: Your laptop shouldn't be the bottleneck. By moving the agent workspace to a remote VM accessed via Tailscale, Zellij, and Mosh, you ensure agents can run continuously uninterrupted. By tying session hooks to text and email notifications, you retain the flexibility to monitor progress and unblock agents from your phone or any device.
A quick warning inspired from XKCD 1319 before we dive in: Beware the automation trap.
The Lore: From Ricing to Agents
If you came from the Unix/Linux world, dotfiles are familiar: .vimrc, .bashrc, .zshrc, .gitconfig, window-manager configs, editor configs, and the other tiny files that quietly encode your preferences and workflow.
There is some funny lore here. Rob Pike has a well-known explanation of how hidden files in Unix grew out of an early shortcut in ls: files beginning with . were skipped so . and .. would not show up in normal listings. That little shortcut accidentally created a durable culture. Configuration files started hiding behind dots, and eventually people began versioning their personal setup as dotfiles repos.
Being a fanboy of vim and ricing linux desktop environments (r/unixporn - SFW I promise!) introduced me to dotfiles back in the day. I used to maintain my dotfiles mainly for my linux desktop ricing when I was using the i3 window manager, vim, ncmpcpp, ranger, etc. which culminated in a keyboard-heavy setup where I took unreasonable pride in rarely moving my hands away from the home row. My old dotfiles repo has a nice little fossil record:
First commit: Sep 7, 2014
Last commit: Nov 27, 2022 (I should really resurrect this or just absorb it into botfiles)
Then life, work, and fatherhood happened. Spending a weekend making your status bar 3% more elegant became harder to justify. But the core pattern of dotfiles remained undefeated: keep your important setup in version control, use symlinks to make machines reproducible, and let the repo become a map of your taste.
The Need for Botfiles
With the rise of CLI-first agentic engineering, that exact pattern is suddenly critical again. We are back to juggling config.toml / settings.json and CLAUDE.md/AGENTS.md files, custom skills, hooks, and provider secrets for Codex and Claude Code configs and behavior preferences.
I realized I didn't want my workflow trapped in whichever agent happened to be winning this month, or whichever vendor I had credits with. Cursor, Claude Code, Codex, OpenCode, Hermes, OpenClaw, etc. all are terrific products in their own right. But I wanted my context and skills to survive outside of them.
More importantly, I didn't want my workflow trapped on a single machine. I wanted the ability to run agents 24/7 on a remote VM without keeping my laptop awake, while still being able to check their progress from anywhere (including phone). I needed my agent setup to travel with me.
So, I resurrected the dotfiles pattern of using symlinks etc. and created the https://github.com/ma08/botfiles/ repo to store and maintain codex/claude code configs.
The important categories are:
codex/AGENTS.md and claude/CLAUDE.md: global instructions and persistent preferences.
codex/skills/ and claude/skills/: reusable workflows like starting tasks, saving status, continuing sessions, reviewing PRs, Gmail/Drive flows, Oracle reviews, and more.
.botenv and .botrc: a two-layer shell bootstrap so non-interactive scripts get the safe core environment and interactive shells get aliases/functions on top.
bin/ and shell/: wrappers and workflow helpers.
docs/: contracts for task metadata and cross-session orchestration.
hook code for notifications and session events.
templates for local secrets without committing real secrets.
The Remote Setup: 24/7 Agents Across Machines
I wanted my agents to keep working even when my laptop was closed, on bad Wi-Fi, or away from my desk. If an agent needed input, I wanted to easily respond from wherever I was (either on phone or laptop with a bunch of applications and terminals open).
I transitioned to using a VM as primary workspace and adopted the following stack:
Tailscale: private network across my laptop, phone, VM, and some production machines.
Mosh: SSH that tolerates roaming and intermittent connectivity much better than vanilla SSH.
Zellij: persistent named terminal sessions.
Zellij Web Client: browser access to specific sessions over my private network.
Termius: iPhone SSH client for quick responses.
Cursor over SSH/Mosh: GUI file browsing, diff review, and edits when terminal-only is too much friction.
The VM gives me a stable, always-on substrate. Zellij gives each task a dedicated, named room. Hooks push the room link directly to my notifications. Cursor gives me a GUI when the diff deserves one. Termius lets me unblock an agent while away from my keyboard.
Skills
Even before skills feature was launched on Oct 16th, 2025 by Anthropic, I started first drafting some of my prompts as markdown files in cursor and saving them because I would often reuse some of them and was afraid of using a long prompt by pressing some key accidentally.
Ever since the skills feature launch, I've adopted them religiously for any workflow that has repetition and made it part of any agentic engineering habit I built.
Out of everything I built, one use case emerged as the absolute king, giving rise to an entire family of skills: context and memory management for tasks.
Task Folder Based Context Management
The most impactful idea in my setup is the task folder. There's a reason why many people have been talking about how filesystem + grep is all you need.
One of the biggest pain points for me was managing parallel coding sessions. A pretty common pattern looked like this:
I started 3-4 sessions in parallel.
I finished 1-2 that day.
The remaining sessions paused somewhere awkward.
A few days later I had to pick them up again after higher-priority work interrupted me.
The only reliable memory was a giant transcript, my own vague recollection, or asking the agent to recap itself.
That is bad for humans. It is also bad for agents. Transcripts are useful but they are too long, too chat-shaped, and often hard to lookup. So I started treating each task as a portable folder using this family of skills:
start-new-task: creates the task folder, captures the initial prompt, pulls tracker (linear/github issue) context when available, and drafts a first-pass plan.
save-task-status: checkpoints the task, updates status.md, reconciles metadata, and makes the current session discoverable later.
get-task-details: prints the active task folder, tracker URL, machine, session, transcript, zellij link, and recap.
continue-task: resumes an existing task from a tracker ref, slug, status file, or zellij session instead of creating duplicate context.
finish-task: standardizes closeout: validation, handoff comments, tracker state, PR/merge readiness, and cleanup.
A typical task folder has:
status.md: the living handoff file. Goal, current state, progress, decisions, artifacts, next steps, tracker metadata.
user_inputs/: immutable original user prompts and clarifications.
user_inputs/input_artifacts/: files, screenshots, references, and captured external inputs.
task-progress-artifacts/: curated outputs and evidence from the work.
task-progress-artifacts/scratchpad/: raw logs, scripts, polling snapshots, temporary captures, and intermediate work.
It is surprisingly simple and boring but it works. The boring folder does a few things:
A future agent can resume without asking me to reconstruct history.
A different coding agent can take over from the current one.
A reviewer can inspect artifacts without opening the full chat.
A bug fix weeks later can find the original design intent.
A task can move between a VM, laptop, Linear issue, GitHub PR, or Notion draft without losing the thread.
As of this draft, a quick local scan across my ~/pro directory found roughly:
2,069 status.md files under context/daily
573 dated task folders at the measured task-folder depth
Many of those files are raw, messy, and not meant for public consumption. The point is that the operational memory exists outside any one chat UI. When shit hits the fan in production, the task folder becomes the closest thing to a design doc to reference.
Cross-Session Management
Often, I used a single session to act as a project planner. It would break down work into tickets, and then each individual ticket got its own coding agent session (often running in parallel).
While I could leverage the status.md files for context, I needed more direct inter-session communication so that each session could:
easily read both the status file and the raw transcript based on the task identifier
message directly into an interactive coding agent session (like how a human sends a new message)
This was mainly useful for having a master orchestrator session. This led to the creation of the following skills:
cross-session-context: read another tracked task/session without taking it over.
cross-session-message: send a bounded message into another zellij-backed session.
Notable Custom Skills
Beyond the task management I have come to appreciate these skills over time:
grill-me: a variant of the famous grill-me skill from @mattpocockuk to interrogate before implementation but with a customization of using structured interactive questions to easily pick options from.
oracle: bundle files and prompts for a second-model review.
ralph: create an iterative autonomous development loop around a spec and fix plan.
pr-autoreview-loop: run a repeatable PR review/fix loop.
developer-message: send a bounded, formatted message directly into an active developer session without breaking its current context.
deep-research: use a combination of deep research APIs from openai, gemini, exa to to generate a comprehensive report from multiple sources.
sync-codex-claude-skills: makes it easy to sync skills across codex and claude.
Hooks: notification UX for parallel agents
My adoption of the hooks feature started with one problem: How do I easily know when an agent needs me?
That problem gets worse when a bunch of sessions are running in parallel. I built hooks around important states:
task completion
waiting for input (claude code has better support for this now than codex as it makes it easy to run a hook on `AskUserQuestionTool` whereas codex doesn't seem to have good support for `request_user_input` tool the last time I checked)
reviewer handoff
PR/CI events when available
task metadata and session links
The notifications go to:
WhatsApp, because I notice it quickly
email, because threads are better for parallel tasks
WhatsApp was useful at first because it was real-time-ish. But a single chat thread becomes chaotic when many sessions are interleaving messages. Email ended up having a much better form factor:
one thread per task
a useful subject line
context from earlier hook messages
easier scanning across multiple active tasks
The hook messages include identifiers like natural language task slug, tracker ID (linear/github issue ID), PR link, zellij session name, zellij web link, machine name, status file path.
The point is that the agent should not silently disappear into a terminal somewhere that I might lose track of.
Zellij as a minimal orchestration substrate
I tried tmux years ago and never really got the hang of it. I mostly used screen for long-running training workloads.
Zellij finally clicked for this agent workflow. The convention I settled on is simple: one named Zellij session per task.
Often a task has multiple panes or tabs: the main Codex/Claude session and a shell for ad hoc commands, ranger browser, logs, test watchers etc.
Named sessions make parallel work much less mysterious. I can list them, attach to the right one, and include their names in notifications.
Interactive Zellij Session picker
I added aliases for common flows:
zja: attach to a Zellij session.
zjs: list/select sessions.
work-here: open an interactive picker for local sessions.
work-ml: open the picker against my ML/VM workspace.
The more useful version is a small work-zellij style utility built around fzf. It lets me browse existing sessions, create a new one, and attach without remembering exact names.
Zellij Web server
The Zellij web server is pretty underrated. With it, I can expose individual named sessions as browser links inside my private network. The hooks can include those links. When I get a notification, I can click straight into the relevant session instead of remembering which terminal window or SSH connection owns it.
I have not seen this feature discussed enough in agentic coding setup threads. Used well, it turns Zellij into a small, composable orchestrator made from boring Linux pieces.
Personal OS: from project memory to global long-term memory
At first, task folders lived inside each project. That worked until it did not.
I was juggling multiple projects, infrastructure, writing, operations, cloud access, product experiments, and personal workflows. A single project repo had a myopic view. Many tasks did not map neatly to any one repo.
So I created a global workspace I call personal_os.
The job of personal_os is to hold the context that cuts across projects:
what I am working on
project maps
cloud access notes
task history
daily context
durable preferences
cross-repo decisions
source material for writing
broader personal/work operating context (tax filing was easier thanks to this setup)
In that world, botfiles is the portable agent/tooling layer, and personal_os is the broader context layer.
This overlaps with the recent "LLM-managed wiki" discourse. @karpathy's llm-wiki.md points at a similar idea: markdown knowledge bases maintained with LLM help so knowledge does not need to be rediscovered from scratch.
I was using my system for a few months before the LLM wiki post. My version is less elegant and more operational. It is the working memory around tasks: plans, inputs, artifacts, decisions, validation, and handoff state. My version serves as the raw human and agent friendly DB on top of which something like the LLM wiki with cross connections can be generated easily. I might give it a try sometime.
Apart from task folders, I have started maintaining files like:
projects.md: information about all of my projects, their repo URLs, where they had stable operational clones, where their production/staging environments were deployed
cloud-access.md: information about CLI access to different clouds like AWS, Azure, Google Cloud. I rarely need to open a GUI browser interface these days to setup/manage cloud resources. Didn't have any disasters with YOLOing cloud stuff yet.
soul/ and SOUL.md: broad information about who I am both professionally and personally. There's a pipeline I have that makes it easy to update using info streams from known sources.
The goal is to give every new session a better starting point than a blank chat box.
Team UX, Hermes, and the supervisor cron pattern
Eventually I hit another ceiling. Even with Zellij, hooks, and task folders, I still had to keep track of too many sessions:
Which issues need pickup?
Which sessions are blocked?
Which PRs are waiting on CI?
Which reviewer comments need action?
Which tasks are "done" but not handed off?
The terminal is powerful, but the UX starts to feel like managing a small team through a pile of shell tabs.
That made me more interested in Slack/Discord-style agent UX. The optimal architecture for agent management starts to look suspiciously like human organization structure:
a chief-of-staff style agent
project-specific worker agents
a general worker
direct escalation to the underlying Codex/Claude session when needed
I experimented with OpenClaw and later Hermes. I did not daily drive OpenClaw much because it needed more setup than I had patience for at the time. Hermes got farther, especially with multiple profiles and a Discord workspace.
I also looked at other "software factory" abstractions. My fear was that overly smooth delegation can hide compounding errors. I have seen enough agentic work to distrust the myth of "just delegate to a team" unless the verification and handoff contracts are strong.
The pattern I started building around Hermes had two cron jobs:
pickup: scans for new work, issue queues, or explicit requests; decides whether to start a new coding-agent session, create task context, or route to a worker.
supervise: scans active tasks, status files, PRs, CI/review state, and stalled sessions; nudges work forward or escalates to me when a human decision is needed.
This worked surprisingly well for a few tasks. Then the time-box I had given myself for software-factory experimentation ended, and non-ricing tasks caught up. I am still working on polishing this setup. Will opensource my full Hermes-based team setup and write more about this setup in detail once I reach a stable state that works well.
This is the eternal problem. At some point, improving the machine becomes the work. Sometimes that is leverage. Sometimes it is procrastination in a nice jacket.
What I would steal from this setup
If you are building your own agent workflow, I highly recommend avoiding cloning my repo as-is. Instead, steal bits and pieces by asking your favorite coding agent to take a look at it. You can copy-paste this prompt:
Read through https://github.com/ma08/botfiles/ and grill me (like the skill in that repo) on what parts I should incorporate into my own setup.
Fin. Send Me Your Scars.
We are still early in this space, and everyone is still figuring out how best to harness these new tools. AGI might already be here, but it is ultimately still a tool we need to leverage well.
I am sure parts of my setup are overbuilt, and I guarantee someone out there has a cleaner version with half the files and twice the taste.
Would love to know if I could have done anything better and learn about your battle scars and the arsenal you've built to traverse this new battlefield. Please comment/DM!