Grady DavisOpen to AI roles

GradyDavis

I build real software with AI, and AI that does real work.

I designed and shipped the platform my company runs on, 33,585 lines across three live sites and a CRM. AI coding agents do most of the typing; I write the spec, read and review the code, catch the errors and research the right way to build it. Four AI agents now run parts of the business, and I use open-weight LLMs just as much as cloud ones. Before software, I drove $10M+ in TikTok Shop GMV and led teams of up to 50.

Based in
Spartanburg, SC · open to remote
Looking for
AI engineering, automation & solutions roles
~/syndicate $ node tools/repo-stats.mjs  lines       33,585  across 5 languages  functions   772  in PHP  migrations  37  schema versions  npm deps    0 ~/syndicate $ curl -sX POST crm.stusyn.com/build-api.php?a=next -H "Authorization: Bearer $AGENT_KEY"{"ok":true,"job":null,"note":"Nothing to build right now."} ~/syndicate $ git push origin main# Deploy to cPanel: build 3 sites → upload over FTPS# open-weight models: Ollama + LM Studio · Qwen (local), Kimi (cloud)
Numbers are counted from the source each time this page builds. The API line is the agent endpoint’s real reply when the queue is empty. Click to skip.
33klines of code across three live sites and a CRM
772PHP functions, plain and framework-free
37database migrations that run themselves on deploy
152end-to-end browser checks across four test suites
4AI agent jobs running on schedules
0npm dependencies. No frameworks, no libraries
Counted from the source by tools/repo-stats.mjs when this page was built.All live in production as of October 2026.

01 How I work with AI

Cloud agents and open-weight models.

I use both every day, about equally. Cloud agents for the heavy building and the jobs that run the business; open-weight models through Ollama and LM Studio for coding, agents and file work.

In the cloud

AI coding agents & scheduled agents

I build with Claude Code and read the code it writes. I also run AI agents on schedules that do real work for the business.

  • Built the whole platform below, 33,585 lines, with AI coding agents: I write the spec, read and review the code, catch the bugs and research the standards it has to meet
  • 4 agent jobs on schedules: prospect research and outreach writing, reply handling, website first drafts and weekly blog drafts
  • Designed the key-protected APIs they call, with every rule and limit enforced in code
  • Built a short-form video agent with its own render engine (paused to save usage)
  • Claude Code
  • Code review
  • Scheduled agents
  • Agent APIs
  • Human review gates
Ollama & LM Studio

Local & open-weight LLMs

I use open-weight models just as much as cloud agents: Qwen running on my own Mac, so private work stays on the machine, and Kimi in the cloud when a job needs a bigger model.

Runtimes
Ollama · LM Studio
Models
Qwen (local) · Kimi (cloud)
Hardware
Mac · 16 GB RAM
  • Coding: a second model for writing and checking code next to the cloud agents
  • Agents: open-weight models driving agent workflows
  • File management: sorting, renaming and organizing files with a local model
  • Running locally in 16 GB means picking model sizes that actually fit
The model proposes. Code enforces.

Agents do the judgment work: research, writing, building. Anything with a rule, like send limits, opt-outs, link allow-lists, job claims and who can see what, lives in plain, tested code an agent can’t talk its way past. And anything a client sees passes a human first.

02 Agents in production

AI that does real work.

Each agent is a scheduled job with one narrow task, an API I designed, rules it can’t bend and a human gate where it matters. Pick one to see how it runs.

Website builder

Running · Twice a day

Every paid website order becomes a first draft without me opening an editor. The agent claims a job, builds the site to our client-site rules and uploads it for my review.

  1. Trigger

    A paid order or won quote creates a build. The client’s kickoff form (or call) marks it ready.

  2. Claim

    POST build-api.php?a=next claims the next job (change requests first) in one guarded update, so two runs can never take the same one.

  3. Build

    Reads the brief, kickoff answers, approved contact details and the client’s files, then builds to templates/CLAUDE.md.

  4. Guardrails

    Paths sanitized, file types allow-listed, 800 files / 60 MB per draft. Stale claims return to the queue after 8 hours; 3 failures and it stops.

  5. Review

    Drafts open in a sandboxed preview: no network, forms can’t post, no cookies. I approve before the client sees anything.

Outreach writer

Running · Weekly · Mon & Thu

Researches local trades and gaming studios, runs a free website checkup or makes a homepage preview where it helps, and writes a personal first email plus two follow-ups.

  1. Trigger

    Monday covers local trades in Upstate SC; Thursday covers gaming studios, creators, esports and gaming businesses.

  2. Research & write

    Finds businesses with published business emails, checks their site and writes the emails.

  3. Check

    out_blocked() skips do-not-contact, existing prospects and contacts. out_links_error() refuses outside links and leftover placeholders.

  4. Send

    The CRM sends, not the agent: weekdays 9–5, a warm-up cap from 8 a day up to 30, threaded follow-ups, one-click unsubscribe.

  5. Circuit breaker

    Replies stop the sequence. Bounces over 8% in 14 days switch outreach off and email me.

Reply handler

Running · Twice a day

Reads replies to outreach and decides what happens next, from a fixed set of actions.

  1. Sort

    Code sorts the mail first: bounces, spam blocks, auto-replies and opt-outs never reach the model.

  2. Read & decide

    Reads real replies and picks one action: reply, interested, decline, handoff or resume.

  3. Enforce

    Only conversations waiting on a reply can be answered, once. Replies count toward the daily send cap.

  4. Record

    interested creates the contact, a qualified deal at the product’s price and a task.

  5. Hand-off

    Unsure? handoff parks it for me with a suggested reply. If I answer myself, the agent steps back.

Blog writer

Running · Weekly · Wednesday

Writes one post a week for syndicatemarketing.co as a draft and sends me the link.

  1. Trigger

    The Wednesday run of the weekly growth task.

  2. Write

    Writes to the blog’s house rules: prices from catalog tags, no made-up stats, clients or results.

  3. Draft build

    Drafts build at their own address with a Draft bar and noindex, and stay off the index, feed and sitemap.

  4. Fail-safe

    The build fails on any unfilled template tag, so a broken post can’t ship.

  5. Publish

    I approve every post. Publishing is one instruction: drop the draft flag, date it, build, push.

Video producer

Paused · Paused Oct 23, 2026

Made two short videos a day for TikTok with our own engine and sent each one to my phone, ready to post. Paused to save plan usage; one switch turns it back on.

  1. Trigger

    Scheduled for about 6:45 AM and 5:45 PM.

  2. Script

    Picks the next topic from a rotation and writes a brief that follows a playbook of hard rules.

  3. Render

    tools/video/ checks the brief, then renders a 1080×1920 video with an original soundtrack.

  4. Deliver

    Sends the video, caption, hashtags and first comment to my phone.

  5. Post

    I post it myself: The TikTok API only allows private posts until an app passes its audit.

03 What I’ve shipped

One person, a whole platform.

Everything here is live and runs Syndicate today. Read the case study for how the pieces fit together. Anything built for a made-up business is labelled as a concept.

Client portal home page with projects, approvals and website care, filled with demo data
Back office

CRM, client portal and billing

One PHP and SQLite app runs every brand: pipeline, contacts, tasks, quotes with online deposits, invoices, bookings, a shared inbox, projects and a client portal.

  • 37 schema migrations that apply themselves on the next page load
  • A paid Stripe order creates the contact, won deal, paid invoice, project, portal access and tasks on its own
  • A demo portal on separate sample data, rebuilt daily, where every form is read-only
PHPSQLiteStripe APIIMAP/SMTPICS
Syndicate Marketing pricing page with every package priced
Commerce

Store, checkout and subscriptions

A cart and four-step Stripe checkout on syndicatemarketing.co, wired straight into the CRM.

  • The server re-prices every cart from the CRM’s catalog; prices from the browser are never trusted
  • Subscriptions, free-month trials, limited offers and creator discount codes, each re-checked at checkout
  • Signed, de-duplicated webhooks, plus a fallback sync that completes an order if a webhook goes missing
JavaScriptStripe CheckoutWebhooksHMAC
Free website checkup tool
Public tool

Free website checkup

Type in any website and get a plain-English report in about a minute.

  • Safe to point at strangers’ sites: every address checked public, pinned, redirects re-checked
  • HTTPS, headers, SEO, speed, broken links and domain expiry
PHPcURLPageSpeed APIRDAP
Lumen Hill Observatory concept site with a WebGL star field
Concept · custom 3D

WebGL particle engine

Hand-written, no libraries: 180,000 stars on desktop that morph between a galaxy, Saturn, a black hole and a planetarium dome as you scroll.

  • Fewer particles on phones and slow devices; falls back without WebGL or with reduced motion
WebGLGLSLJavaScript
Security

Passkeys from scratch

Plain WebAuthn with no libraries: a CBOR reader, ES256 and RS256 checked with openssl_verify. One passkey works across the CRM, ads and wiki.

  • Argon2id, a breached-password check that never sends the password, session limits and a security log with alerts
  • Built against OWASP Top 10:2025, ASVS 5.0 and NIST SP 800-63B-4
WebAuthnTOTPArgon2idCSP
Analytics

Site Stats

Privacy-first analytics I run instead of Google Analytics, for our sites and every client’s.

  • No cookies: visitors counted with a salted hash that rotates daily; IP addresses are never stored
  • Goals, campaigns, outbound clicks and monthly reports, on their own database
PHPSQLiteJavaScript
Monitoring

Website care

Uptime checks every 15 minutes, SSL and domain expiry, weekly security scans and PageSpeed tests, and a monthly web report for each client.

  • Two failed checks in a row open an incident, email us (and the client, if they want) and add a task
  • Report links signed with HMAC, one per site per month
CroncURLPageSpeed API
Delivery

Build & deploy

No frameworks and zero npm dependencies: small Node build scripts, and GitHub Actions deploys three sites over FTPS on every push.

  • Finds each live folder by its own files and stops if anything is ambiguous; never deletes, never uploads config or data
  • A build fails on any unfilled template tag, so a typo can’t ship
NodeGitHub ActionslftpApache
Case study The back office behind the agency

How the store, CRM, client portal and growth tools fit together: the problem, what happens when a client clicks Pay, and the calls I made along the way.

Read the case study →

04 Read the code

Straight from production.

Five excerpts copied as-is from the live codebase, with the reason each one exists. I can walk you through any of them line by line. The highlighting is a few dozen lines of JavaScript on this page.

stripe-webhook.php
$ev = stripe_verify($payload, (string)($_SERVER['HTTP_STRIPE_SIGNATURE'] ?? ''), stripe_key('stripe_webhook_secret'));
if (!$ev || empty($ev['id'])) { http_response_code(400); exit('{"ok":false,"error":"Signature check failed"}'); }

// Each event is handled once, even when Stripe sends it again.
try { q('INSERT INTO stripe_events (id, type, created_at) VALUES (?,?,?)', [$ev['id'], (string)($ev['type'] ?? ''), now()]); }
catch (PDOException $e) { exit('{"ok":true,"result":"already handled"}'); }
try {
    $result = shop_handle_event($ev);
    q('DELETE FROM stripe_events WHERE created_at < ?', [date('Y-m-d H:i:s', time() - 60 * 86400)]);
    echo json_encode(['ok' => true, 'result' => $result]);
} catch (Throwable $e) {
    q('DELETE FROM stripe_events WHERE id = ?', [$ev['id']]); // let Stripe retry
    error_log('Stripe webhook ' . ($ev['type'] ?? '') . ' failed: ' . $e->getMessage());
    http_response_code(500);
    echo '{"ok":false}';
crm/stripe-webhook.php · lines 9–23

Handling a payment exactly once

Stripe can send the same event more than once. The handler verifies the signature, then lets the database decide whether it has seen the event: the primary key does the de-duplicating, with no race.

  • HMAC-SHA256 signature with a 5-minute replay window
  • Insert-first de-duplication on the event ID
  • If handling fails, the row is removed so Stripe’s retry gets processed
checkup.php
function ck_ip_public(string $ip): bool {
    if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) return false;
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
        $n = ip2long($ip);
        foreach ([['100.64.0.0', 10], ['192.0.0.0', 24], ['198.18.0.0', 15], ['192.88.99.0', 24], ['224.0.0.0', 4], ['240.0.0.0', 4]] as [$net, $bits]) // shared, protocol, benchmark, relay, multicast, reserved
            if (($n & (-1 << (32 - $bits))) === (ip2long($net) & (-1 << (32 - $bits)))) return false;
        return true;
    }
    $l = strtolower($ip);
    return !preg_match('/^(fc|fd|fe[89ab]|ff|::ffff:|64:ff9b:|2001:db8:|2002:)/', $l);
}
// The address to connect to: an IP, '' (not found) or '!' (points somewhere private). Every address the name has must be public.
function ck_ip(string $host): string {
    static $cache = [];
    if (isset($cache[$host])) return $cache[$host];
    $ips = gethostbynamel($host) ?: [];
    if (function_exists('dns_get_record')) foreach ((array)@dns_get_record($host, DNS_AAAA) as $r) if (!empty($r['ipv6'])) $ips[] = $r['ipv6'];
    if (!$ips) return $cache[$host] = '';
    foreach ($ips as $ip) if (!ck_ip_public($ip)) return $cache[$host] = '!';
    return $cache[$host] = $ips[0];
}
crm/app/checkup.php · lines 43–63

Scanning strangers’ websites safely

The free checkup fetches any URL a visitor types, which is a classic way to trick a server into probing its own network. Every address a host resolves to must be public, or the scan refuses.

  • Private, reserved, shared, benchmark and multicast ranges refused, IPv4 and IPv6
  • Every DNS answer must pass, not just the first
  • The checked IP is then pinned for the actual request
builds.php
function build_claim(): ?array {
    if (!build_on()) return null;
    $b = one("SELECT * FROM builds WHERE status IN ('ready','changes') ORDER BY CASE status WHEN 'changes' THEN 0 ELSE 1 END, updated_at LIMIT 1");
    if (!$b) return null;
    $claim = q("UPDATE builds SET status = 'building', claimed_at = ?, attempts = attempts + 1, updated_at = ? WHERE id = ? AND status IN ('ready','changes')", [time(), time(), $b['id']]);
    if ($claim->rowCount() === 0) return null;
    return build_job(build_row((int)$b['id']));
}
crm/app/builds.php · lines 124–131

Claiming a job exactly once

Two scheduled runs could ask for work at the same moment. The claim is a conditional update: only the run whose update actually changes the row gets the job.

  • Change requests jump ahead of new builds
  • No locks needed: rowCount() settles the race
  • Each claim counts an attempt, so a stuck job stops after three
passwords.php
function pw_breached(string $pw): int {
    $sha = strtoupper(sha1($pw));
    $url = 'https://api.pwnedpasswords.com/range/' . substr($sha, 0, 5);
    $hdr = ['Add-Padding: true', 'User-Agent: Syndicate-Security-Check'];
    $raw = false;
    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $hdr, CURLOPT_TIMEOUT => 5, CURLOPT_CONNECTTIMEOUT => 3]);
        $raw = curl_exec($ch);
        if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) !== 200) $raw = false;
        curl_close($ch);
    } else {
        $raw = @file_get_contents($url, false, stream_context_create(['http' => ['header' => implode("\r\n", $hdr), 'timeout' => 5]]));
    }
    if (!is_string($raw) || $raw === '') { error_log('Breached-password check unreachable; password allowed.'); return -1; }
    $tail = substr($sha, 5);
    foreach (preg_split('/\r?\n/', $raw) as $line) {
        [$suffix, $count] = array_pad(explode(':', trim($line)), 2, '0');
        if (hash_equals($tail, strtoupper($suffix))) return (int)$count; // padding rows have a count of 0
    }
    return 0;
}
crm/app/passwords.php · lines 44–65

Checking breached passwords without sending them

New staff passwords are checked against Have I Been Pwned using k-anonymity: only the first 5 characters of the hash leave the server, and padded responses hide which range was asked for.

  • Constant-time comparison with hash_equals
  • If the service is down, the password is allowed and the outage is logged
  • Never sends or stores the password itself
Excerpts from a private codebase. The case study shows how it all fits together.Ask for a walkthrough

05 How I build

Spec, build, review, test, ship.

The same loop for every change, whether it’s a typo or a payment flow.

  1. Spec

    I research how it should be built first (OWASP, NIST, the RFCs, the vendor’s docs), then write it into CLAUDE.md: 1,225 lines the agents read before they touch anything.

  2. Build

    AI coding agents write most of the code from that spec, one scoped task at a time, so I can follow every change.

  3. Review

    I read the code. I catch the errors, security holes and shortcuts, send them back, and make the calls on architecture and what we promise customers.

  4. Test

    Playwright runs the real flows against a local copy with a mock Stripe server and fake mail: 152 checks across store, quotes, booking and security.

  5. Ship

    A push to main builds three sites and deploys them over FTPS. Database migrations run themselves on the next page load.

How I actually work

AI does most of the typing; the engineering is mine. I read and understand the code, spot bugs and bad patterns before they ship, and research best practices instead of taking an agent’s word for it. That isn’t vibe coding: it’s specifying, reviewing, testing and owning what goes live.

06 This page

The page is the demo.

Plain HTML, CSS and JavaScript with nothing borrowed. It reads fully with JavaScript off, respects reduced motion and works by keyboard. Here’s what it’s made of and what it weighs, measured live.

The codebase, by language

33,585 lines

Counted from 312 source files when this page was built, leaving out demo sites, fonts and content.

  • PHP18,67056%
  • HTML6,50919%
  • CSS4,36313%
  • JavaScript3,64211%
  • Python249<1%
This page, right now

Measured in your browser

Read from the Performance API after the page loaded.

Transferred
—
JavaScript
—
Requests
—
Page elements
—
DOM ready
—
Frameworks
0

Cached files can show as small or zero. With JavaScript off, the dashes stay and everything else still works.

07 Experience

Where I’ve worked.

Building my own businesses since 2019, after nine years of running stores, teams and partner accounts. Customer-facing experience is what makes the technical work land.

  1. 2019 — PRESENTSpartanburg, SC · Remote

    Founder & Builder

    Syndicate Holdings Group LLC · Syndicate Marketing · Creator Ops Media

    • Designed and shipped the software the company runs on, building with AI coding agents and reading and reviewing the code myself: three live sites, a CRM, a client portal, a store with Stripe subscriptions, analytics, monitoring and a help center (33,585 lines).
    • Built and run 4 scheduled AI agent jobs for outreach, reply handling, website drafts and blog drafts, behind APIs with rules enforced in code and human review gates.
    • Use open-weight LLMs through Ollama and LM Studio (Qwen locally, Kimi in the cloud) for coding, agents and file management.
    • Delivered client sites like Kirby’s Home Improvement, live with calls and quote requests tracked in our own analytics.
  2. FOUNDERTikTok Shop · consulting since late 2026

    Founder & Lead TikTok Shop Strategist

    Creator Ops Media

    • Drove more than $10M in TikTok Shop GMV for brands including Intake Breathing and Rap Snacks.
    • 2024–25: led classes and coached smaller agencies; among the first to test new TikTok Shop features.
  3. 2016 — 2025Upstate South Carolina

    Before software: operations & partners

    Nine years running stores, teams and partner accounts

    General Manager7-Eleven · Spartanburg2023–2025
    Manager, Dealer RelationsAmerican Credit Acceptance · network +10% in a year2022–2023
    Security SupervisorSecuritas · team of 502021–2022
    PM Assistant ManagerCircle K · team of 252018–2021
    Shift LeadDollar General · team of 92016–2018

08 What I’m looking for

Roles where I fit.

AI work that sits between the people with the problem and the system that solves it. Remote, or based from Spartanburg, SC.

AI solutions & implementation

Take a business problem, design the agent workflow, build it and get it running. I did exactly that for my own company.

AI automation & agent operations

Run agents on schedules with real guardrails, watch what they do and tighten the rules when they drift.

Solutions or sales engineering

B2B sales and partner work (a dealer network up 10% in a year), and I can build the demo myself.

Forward-deployed engineering

Sit with the customer, learn the workflow, ship the fix. Nine years of operations taught me the first two.

Technical PM for AI products

I write specs that agents build from, and I own the result end to end: tests, launch and the promises it makes.

AI education & enablement

I’ve led classes for other agencies. I’d like to teach teams to build with AI next.

09 Skills

The stack I ship in.

Everything in the codebase above, plus the local setup on my own machine.

AI & agents Cloud

  • Claude Code
  • Code review
  • Debugging
  • Agent workflow design
  • Agent APIs
  • Guardrails in code
  • Human-in-the-loop review
  • Spec writing
  • Best-practice research

Local & open-weight LLMs

  • Ollama
  • LM Studio
  • Qwen (local)
  • Kimi (cloud)
  • Local coding
  • Local agents
  • File management

Backend

  • PHP
  • SQLite
  • JSON APIs
  • Webhooks
  • Cron jobs
  • Schema migrations
  • IMAP/SMTP

Frontend

  • HTML
  • CSS
  • JavaScript, no frameworks
  • WebGL
  • Accessibility
  • Performance

Security

  • WebAuthn passkeys
  • TOTP
  • Argon2id
  • CSP & headers
  • SSRF protection
  • HMAC signatures
  • OWASP

Ship & integrate

  • Git & GitHub
  • GitHub Actions
  • Playwright
  • Node build scripts
  • Stripe API
  • PageSpeed API
  • Apache & LiteSpeed
  • SPF/DKIM/DMARC
Open to AI roles

Let’s build.

Email me and I’ll reply within one business day. References on request.