DEV Community

Casey Li
Casey Li

Posted on

Before a Free Coding Agent Sees Your Repo: A Preflight Gate

Most arguments about free coding agents are arguments about capability. The question that actually decides outcomes is routing: which work should never reach a free model tier at all. Teams that answer this once stop re-litigating it every sprint. Teams that answer it per task end up with a review queue nobody trusts.

What follows is a field guide to the negative case, encoded as a gate. It reads the repository, not the task description, because people describe their intentions optimistically and directories do not. The gate returns an exit code, and the exit code decides the route.

The repository is evidence; the prompt is a claim

A prompt saying "small refactor, no sensitive data" is an assertion. git ls-files is a fact. The asymmetry matters, because a mis-scoped task sent to a paid model costs money, while the same task sent to a free tier can cost a credential, a customer record, or a compliance finding. Price is the wrong axis for the decision.

AI fatigue, when it is not simply model fatigue, is often routing fatigue: the recurring cost of deciding, badly, where each piece of work belongs. A gate turns that recurring decision into a file that can be reviewed once, versioned, and argued with deliberately instead of repeatedly.

The script below is a template, not a shipped tool. It has not been run against an unknown repository, and every check in it is meant to be adapted before anyone trusts it.

#!/usr/bin/env bash
# gate.sh — may work on this repo be routed to a free model tier?
# Exit 0 = free tier acceptable; 10 = free tier with restrictions; 20 = do not route.
set -u

repo="${1:-.}"
reasons=()
code=0

block() { reasons+=("BLOCK  $1"); code=20; }
limit() { [ "$code" -lt 20 ] && code=10; reasons+=("LIMIT  $1"); return 0; }

# 1. Tracked credential-shaped files are a stop, never a warning.
if git -C "$repo" ls-files | grep -Eq '(^|/)(\.env($|\.)|id_rsa|id_ed25519|[^/]*\.(pem|p12|pfx))$'; then
  block "tracked credential-shaped files"
fi

# 2. Secret-shaped literals in tracked source.
if git -C "$repo" grep -InE '(sk-[A-Za-z0-9_-]{20,}|ghp_[A-Za-z0-9]{30,}|AKIA[0-9A-Z]{16})' >/dev/null 2>&1; then
  block "secret-shaped literal in tracked source"
fi

# 3. Uncommitted work means the tree is not the artifact under review.
if [ -n "$(git -C "$repo" status --porcelain)" ]; then
  limit "dirty worktree; commit or stash before the run"
fi

# 4. Data classification is explicit, because defaults are always optimistic.
if [ -f "$repo/DATA_CLASSIFICATION" ]; then
  class="$(head -n1 "$repo/DATA_CLASSIFICATION" | tr -d '[:space:]')"
  case "$class" in
    public|internal) : ;;
    *) block "data classification '${class}' requires a private route" ;;
  esac
else
  limit "no DATA_CLASSIFICATION file; scope to internal-only work"
fi

# 5. Production wiring in the same tree narrows what a task may touch.
if git -C "$repo" grep -IlE '\b(prod|production)\b' >/dev/null 2>&1; then
  limit "production references present; scope the task to a subdirectory"
fi

printf 'gate=%s\n' "$code"
if [ "${#reasons[@]}" -eq 0 ]; then printf 'no findings\n'; else printf '%s\n' "${reasons[@]}"; fi
exit "$code"
Enter fullscreen mode Exit fullscreen mode

Reading the result is the method. Exit 0 means the tree is clean, classified, and free of secret shapes, so the free tier becomes the default route rather than an exception. Exit 10 means the work is admissible but must be scoped to a subdirectory with a written reason. Exit 20 means the repository has a problem that no model choice can fix.

Exit Signal Route
0 Clean, classified, no secret shapes Free tier is the default
10 Admissible but scoped Free tier on a subdirectory, with a receipt
20 Evidence of exposure Local or private route; repair the repo first

The 10 branch is where discipline leaks. A limit that is never recorded becomes a block that is never enforced, and a block that is never enforced becomes an incident that is explained away. Recording the decision is cheap compared with reconstructing it after the fact.

# Append one line per run so the route decision survives the sprint.
receipt() {
  printf '%s gate=%s head=%s dirty=%s\n' \
    "$(date -u +%FT%TZ)" "$1" \
    "$(git rev-parse --short HEAD 2>/dev/null || echo no-git)" \
    "$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')" \
    >> .free-tier-runs.log
}

./gate.sh . ; receipt $?
Enter fullscreen mode Exit fullscreen mode

The free server is a staging decision

A free server option changes where the work runs, not what the work is allowed to touch. The exit conditions are therefore about state and reachability, not about performance. If a job needs inbound connections into a private network, a long-lived secret, persistent disk the team later grows attached to, or an audit trail someone will eventually request, the free server is the wrong host and no amount of convenience changes that.

Ephemeral is fine. Stateless is fine. A build that can be recreated from a commit hash in one command is fine. Anything whose loss would require a meeting is not.

This is precisely the shape MonkeyCode presents: free model access plus a free server option, which is why a gate is the first thing to write and the last thing to remove. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The allowance itself is operator-supplied and changes over time; confirm the current token figure and any server limits on the project's own documentation before planning capacity around them, because a number quoted in a blog post is not a contract.

When to leave

Three signals say the free route has stopped paying for itself. The gate blocks more work than it passes, which means the repository is the problem and the tier is a distraction. Reconstructing why a free run failed takes longer than writing the patch would have taken. Or the review queue grows monotonically for a week while nobody can say which runs were free and which were not.

Each of those is an exit criterion, and each is observable without a benchmark. None of them require comparing model quality, which is the comparison that consumes the most argument and settles the least.

Who should not adopt this

Teams without version-control discipline should skip the gate entirely; on an untracked repository it inspects nothing and returns confidence it has not earned. Regulated workloads where any third-party route is disallowed do not need a script, only a policy. Solo prototypes where nothing is at risk will find the gate pure overhead, and that is a legitimate answer. The last group is anyone who cannot state the data classification of the repository in front of them, which is a block rather than a task.

A gate is not a security review. It catches the boring failures, the ones that recur, and it does so in under a second on most trees. The interesting failures still need a person.

If gate.sh exits 0 on a repository, that is the moment the free tier at MonkeyCode is worth an actual run rather than another opinion piece.

Top comments (0)