# Instagram Owner Yes: the approval gate (free sample)

**One file that answers one question before anything goes on your Instagram: did the owner approve this exact caption and alt text?**

From the upcoming Instagram Manager Workflow with Owner Yes, version 1.0, 2026-11-03. By PaperChaseWebb Inc. Python 3.8 or newer, no installs.

## The rule

Nothing is approved or posted unless the owner approved that exact version. "Looks good" in a chat does not count once the caption changes. The fingerprint makes that checkable.

## Try it (5 minutes)

1. Save `gate_mini.py` and `week.csv` from below into one folder.
2. Run `python3 gate_mini.py check week.csv --owner "Dana Reyes"`. You should see `2 rows, 0 errors`.
3. Change one word in P1's caption and run it again. You should see `P1: caption or alt text changed after approval`.
4. To approve a post yourself: read it, run `python3 gate_mini.py fingerprint week.csv P1`, paste the result into `approved_sha`, and put your name in `approved_by`.

What it checks: caption over 2,200 characters, more than 5 hashtags (Instagram's Help Center limit, read 2026-11-03), feed or carousel image with no alt text, approved by someone other than the owner, the drafter approving their own post, and any change after approval.

## The weekly loop (the full kit runs all of it)

1. **Study**: last week's own numbers, one pattern to repeat.
2. **Plan**: 3 to 5 concepts; the owner selects or kills.
3. **Produce**: captions and alt text, every claim labeled.
4. **Queue**: the checker clears the batch.
5. **Approve**: the owner reviews the week in one sitting.
6. **Post**: the owner posts from a sheet of approved, unchanged posts.

## The full kit adds

- 20 checks instead of 6: owner selection, media files with fingerprints, claim labels with evidence, releases for people in posts, days inside the week, and a cross-check that any "comment WORD" call to action has a live, approved reply in Comment to DM Delivery.
- `approve.py`: a terminal review that refuses agent sessions.
- The posting sheet and a `posted` log that refuses anything unapproved.
- The Monday study note from your own insights.
- Agent rules for Grok Bot, Claude Code, Codex and Hermes, a fictional example week and 30 tests.

The full version, Instagram Manager Workflow with Owner Yes, is coming soon.

## The files

#### file: mini/gate_mini.py
~~~~python
#!/usr/bin/env python3
"""Free sample: the owner-yes gate for one week of Instagram posts, in one file.

  python3 gate_mini.py check week.csv --owner "Your Name"
  python3 gate_mini.py fingerprint week.csv P1

week.csv columns: id, day, format, caption, alt_text, status, drafted_by, approved_by, approved_sha
status is one of: drafted, held, approved, posted.

The rule: nothing is approved or posted unless the owner approved that exact caption and alt text.
When you approve, run `fingerprint` and paste the result into approved_sha. Edit the caption later
and the check fails until you approve again. The full kit adds selection, claims, media files,
releases, the DM keyword cross-check, a terminal review, the posting sheet and the study note.
"""
import csv, hashlib, re, sys

CAPTION_MAX, HASHTAG_MAX = 2200, 5


def fingerprint(row):
    return hashlib.sha256((row["caption"] + "\x00" + row["alt_text"]).encode("utf-8")).hexdigest()


def check(path, owner):
    with open(path, newline="", encoding="utf-8-sig") as f:
        rows = list(csv.DictReader(f))
    errs = []
    for r in rows:
        i, st = r["id"], r["status"]
        if len(r["caption"]) > CAPTION_MAX:
            errs.append(f"{i}: caption over {CAPTION_MAX} characters")
        if len(re.findall(r"(?<![\w&])#\w+", r["caption"])) > HASHTAG_MAX:
            errs.append(f"{i}: more than {HASHTAG_MAX} hashtags")
        if r["format"] in ("feed", "carousel") and not r["alt_text"].strip():
            errs.append(f"{i}: image post without alt text")
        if st in ("approved", "posted"):
            if r["approved_by"].strip().lower() != owner.lower():
                errs.append(f"{i}: approved_by is not the owner")
            elif r["approved_by"].strip().lower() == r["drafted_by"].strip().lower() and r["drafted_by"].strip().lower() != owner.lower():
                errs.append(f"{i}: the drafter approved their own post")
            if r["approved_sha"] != fingerprint(r):
                errs.append(f"{i}: caption or alt text changed after approval")
    return rows, errs


def main(argv):
    if len(argv) >= 4 and argv[1] == "check" and argv[3] == "--owner" and len(argv) == 5:
        rows, errs = check(argv[2], argv[4])
        for e in errs:
            print("ERROR", e)
        print(f"{len(rows)} rows, {len(errs)} errors")
        return 1 if errs else 0
    if len(argv) == 4 and argv[1] == "fingerprint":
        with open(argv[2], newline="", encoding="utf-8-sig") as f:
            for r in csv.DictReader(f):
                if r["id"] == argv[3]:
                    print(fingerprint(r))
                    return 0
        print("no such id")
        return 2
    print(__doc__)
    return 2


if __name__ == "__main__":
    sys.exit(main(sys.argv))
~~~~

#### file: mini/week.csv
~~~~csv
id,day,format,caption,alt_text,status,drafted_by,approved_by,approved_sha
P1,2026-11-10,carousel,"Three glazes, one kiln, three very different blues. Swipe left to right: thin, medium, heavy. #ceramics #glaze","Three square test tiles glazed pale, medium and deep blue",approved,grok-bot,Dana Reyes,de94e717c30500fd79f4f84959cf1ab8c0f77650debb1c73d46c0aef07508863
P2,2026-11-11,feed,"What happens to a mug between the wheel and your shelf. #handmade","Four photos of one mug from wet clay to glazed",drafted,grok-bot,,
~~~~
