Към съдържанието

Meta Harness

Слой над средите на агентите за програмиране, под който работи всеки мой проект

Роля
Проектирам и поддържам
Статус
В процес
Код
Частно хранилище
Технологии
BashPythonMarkdownJSONClaude Code pluginsCodexCursorOrcaWSL2Git hooksGitHub ActionsShellCheck
Изход от терминала на PreToolUse hooks на Meta Harness. Четири симулирани действия на агент са отказани, всяко с код на изход 2, оранжев ред „BLOCKED“ с причината и ред с указание за поправка: сляпо git commit с -a, рекурсивно изтриване на домашната директория, четене на .env файл и запис в .env файл. Git add с ограничен обхват е разрешен с код на изход 0, а последният ред съобщава, че самопроверката на защитата минава.
Когато агент посегне към опасна команда, защитата с hook отказва и казва какво да се направи вместо това.

В числа

48

проекта в регистъра, които платформата управлява

12

постоянно активни правила на платформата, инсталирани на всяка машина

11

skills за работния процес, всеки с поне един положителен случай на задействане

53

тестови случая за задействане, 8 от които пазят от фалшиви задействания

90

случая в таблицата на самопроверката на защитата за команди, 57 блокират и 33 разрешават

8

проекта със собствени набори правила на проектния слой

Проблемът

Агентите за програмиране пишат бързо, но трудно се връщат от грешна посока. Анализ на собствените ми записи на сесии откри грешката, която срещах най-често: агент твърди, че е свършил работа, която не е проверил. Claude Code и Codex идват всеки със своя обща среда за работа на модела, а общата среда не познава моите правила, моите проекти и какво отказвам да позволя. Правилата, поставени ръчно във всяко хранилище, се разминаваха, а правило, което нищо не проверява, е само предложение. Работя в много хранилища на Windows, затова настройката трябваше да се инсталира с една команда, без пароли и ключове.

Подходът

Правилата започнаха като лични файлове. Превърнах ги в платформа, моя плъгин Valox: каталог (marketplace) с плъгини за Claude Code, който доставя skills за работния процес, проверяващ агент и защитни hooks, регистър с постоянно активни правила и няколко малки инструмента за командния ред, които инсталират, проверяват и синхронизират всичко това. Всеки проект работи под него и записва точната версия, от която е синхронизиран. Позицията е записана в ADR (запис на архитектурно решение): когато изборът е между повече текст с инструкции и проверка, която пада, добавям проверката. Работата минава през задача (issue), план (blueprint), изграждане (build) и pull request, с две точки за одобрение от човек: одобрение на плана и pull request, който етапът на изграждане никога не отваря сам. Същата платформа е основата на моята настройка за агенти Orca, която пренася правилата и защитите между доставчици на модели.

Изход от терминала на четири проверки на Meta Harness. Линтерът изброява пет проверки (обща дължина на текстовете, които задействат уменията, frontmatter, изключени думи, препратки към файлове, фрази, издаващи AI) и завършва с „OK“, нула грешки, нула предупреждения. Проверката на покритието на условията за задействане съобщава, че и деветте skills са покрити от 39 тестови случая. Самопроверката на шаблоните съобщава 25 шаблона за откриване и минава. Предварителната проверка „doctor“ показва шест проверки на зависимости, всички „PASS“.
Проверките, през които минава всяко правило и всеки skill, преди да получи разрешение за пускане.

Как работи

  1. Три слоя, по едно място за всяко правило

    Всяко правило, skill, hook или скрипт живее в точно един слой: L1 платформа за всичките ми проекти, L2 проект за едно хранилище, L3 машина за неща, които никога не бива да се записват в Git. Причината е бюджетът на контекста. Правило от L1 се зарежда във всяка сесия на всеки проект, така че инвариант, специфичен за един проект, поставен на L1, товари несвързана работа. Повишаването е видимо преместване на файл от consumers/<project>/rules/ към shared/rules/, щом втори проект поиска правилото, а понижаването не струва нищо.

  2. Един източник, закрепен към версия, пренесен във всеки инструмент

    Skills, проверяващият агент и hooks се доставят като плъгин на Claude Code от локален каталог (marketplace) в папка. Правилата се инсталират като отделни файлове, следени от манифести, така че оттеглено правило се премахва, а написано на ръка в същата папка остава недокоснато. Малки скриптове за генериране пренасят същите правила и skills в Codex, Cursor и Grok. Всяко свързано хранилище записва в .valox.json пълния 40-символен commit, от който е синхронизирано, а CI му проверява съответствието спрямо този закрепен commit, а не спрямо движещия се main на платформата. В началото на сесията инструмент за диагностика (doctor) отпечатва по един ред за всяко разминаване, а първият отговор на агента трябва да го спомене.

  3. Защити, които могат да откажат

    Hooks от типа PreToolUse блокират четири вида действия: принудително изпращане (force-push), което пренаписва публикуваната история, рекурсивно изтриване, насочено към корена, домашната или работната папка, четене на файл с пароли или ключове в записа на сесията и слепо добавяне за commit с git add -A. Защитата за команди разбира командите с shlex на Python, защото обединяването с AND на регулярни изрази върху целия низ караше безопасни команди да изглеждат опасни, а защита, която вдига фалшива тревога, се изключва. Самопроверката ѝ подава обратно през скрипта 90 случая от таблица като истински данни за hook. Локално hook за commit-msg отхвърля приписване на AI като съавтор, а hook за pre-commit отказва директни commit в основния клон и добавени за commit тайни.

  4. Един проверяващ агент със строго заключение

    Единственият собствен субагент е проверяващ агент само за четене, със свеж контекст, така че да оценява резултата без разговора, който е направил плана да звучи убедително. Той трябва да отговаря в строга форма: VERDICT със стойност PASS, REVISE или BLOCK, находки с посочени файл и ред, таблица VERIFICATION, която изброява всяка команда като PASS, FAIL или NOT RUN, оставащ риск и препоръка. NOT RUN е допустим отговор, а свободният текст би го оставил да изчезне.

  5. Профилите взвеждат възможности, а действието все пак пита

    Всеки профил изброява проектите, които може да докосва, и опасните възможности, взведени за него: търговия на живо, пускане в продукция, имейл, управление на работния плот, платено генериране и разрушителни операции върху база данни. Двата списъка започват празни и се вграждат в правилата на самата сесия, така че агентът може да заяви преди действие, че дадена възможност не е взведена. Взвеждането премахва общия отказ и запазва проверката в момента на действието: поръчка на живо пак изисква потвърждение, което назовава пазара и размера.

  6. Една основа под няколко доставчици на модели

    Orca, външен инструмент с MIT лиценз, който пуска и координира терминали на агенти, работи на моя компютър в собствена WSL дистрибуция и се стартира с една команда. Плащам за най-високия план при всеки доставчик: четири абонамента Claude Max, два абонамента ChatGPT Pro за Codex и SuperGrok Heavy, около 1 500 USD месечно, с по един вход за акаунт. Доставчиците определят цената на тези планове много под това, което същата употреба струва през API, затова настройката разпределя работата между акаунтите на Claude и Codex и изразходва квотата на всеки акаунт, преди прозорецът ѝ да се нулира. Инструменти за отчитане на квотите съобщават идентичността и прозорците на ползване на всеки акаунт, а една команда за състояние показва услугите, средата за изпълнение и всеки влязъл акаунт. Платформата е основата, върху която е изградена тази настройка.

Три колони с изход от терминала, които изброяват 76 случая от самопроверката на защитата за bash. Всеки ред започва със зелено „ok“, а после „block“ в оранжево или „allow“: force push, рекурсивни изтривания, четене на файлове с данни за достъп, сляпо добавяне на файлове за commit и вратички за заобикаляне в git, до разрешени случаи, които приличат на забранените, като force-with-lease. Последният ред съобщава, че самопроверката е „OK“.
Всяко правило за блокиране е тествано с формите на командите, които трябва да хване, и с близките до тях случаи, които трябва да пропусне.

Какво избрах и какво отпадна

Избрах

Доставяне на инструментите като каталог с плъгини през вградената инсталация на Claude Code

Пред

Скрипт за синхронизация, написан на ръка

Собствен скрипт за синхронизиране би правил наново нещо, което средата вече прави, и би станал най-голямото непроверено парче код на платформата.

Избрах

Правила като отделни markdown файлове

Пред

Един генериран файл с инструкции, импортиран от всяко хранилище

Ранна версия правеше така, генерираният файл се разминаваше с източниците си и никой не можеше да каже кое копие важи. Един голям файл също зарежда всяко правило във всяка сесия и изключва зареждането само за определени папки.

Избрах

Блокират детерминирани проверки; оценки (evals), давани от модел, не се доставят

Пред

Набор от тестове за резултата, оценяван от модел, в нощен пуск на CI

Изисква ключ, струва изчислителни разходи за модела при всеки пуск и дава само препоръчителна оценка. Единствената блокираща проверка е покритието на задействанията: всеки skill има нужда от положителен случай, а всеки случай от причина в един ред, като всичко се проверява за по-малко от секунда, без мрежа и без модел.

Избрах

Платформата никога не записва настройките ми на Claude Code

Пред

Включване на автоматичен режим (auto mode) по време на първоначалната настройка (bootstrap)

Инструмент, който разширява собствените си права, отвън изглежда същото като инструмент, който е бил убеден да ги разширява. Цената е записана: никой път в платформата не включва автоматичния режим.

Резултатът

Всеки мой проект работи под него: 12 постоянно активни правила, 11 skills за работния процес и набори правила на проектния слой за 8 хранилища, а той е основата на моята настройка Orca. Първата версия беше атакувана от независими агенти за преглед в три кръга. В първия кръг се оказа, че всеки проект би получил тихо нула правила, докато всяка проверка показва зелено; следващите кръгове откриха скенер, който сканира нула файла, и невидим управляващ байт, който изключваше регулярен израз. Защитите издържат в употреба: в други сесии Codex отказа да разшири собствения си списък с разрешени проекти, дори с моето съгласие в чата, а проверяващ агент отказа да пипа хранилище, което липсва в профила му. Ограниченията са записани в хранилището. Защитата на клоновете от страна на сървъра връща HTTP 403 при моя план, така че локалният hook за pre-commit е единственият слой, който може да откаже, а --no-verify го заобикаля. ADR-0003 приема, че нищо не измерва дали работният процес се подобрява. ADR за топологията ограничава агентите, които пишат паралелно, до трима плюс собственика, а екипите ми от агенти в други хранилища работят много по-широко; още не съм съгласувал двете. Известно ограничение на настройката Orca: сигналите за завършване, които събуждат координатора, стигат до координатор, работещ вътре в WSL, но не и до Windows Codex Desktop или сесия на Claude под Windows, а този път не е изграден.

Какво следва

Да направя хранилището публично след почистване от тайни, което безплатно връща защитата на клоновете и премахва токена за четене, който всяко свързано хранилище изисква, докато платформата е частна.

Бележки от практиката

От търговската система

Две копия на един и същ AI се бият

Веднъж загубих един следобед заради схватка между две копия на един и същ AI, а и двете ги бях пуснал аз.

Две сесии на Claude Code споделяха един сървър, на който работеха автоматичните ми търговски демони. Първата започна като въпрос как да отворя един сайт от телефона си, после сама се назначи за пазач на папката с търговската система и активира собствени програми за наблюдение. Часове по-рано бях спрял да я ползвам и бях преминал към нова сесия, за да продължа разработката. Новата сесия знаеше, че съществува друга, паралелна. Не знаеше, че към старата още постъпват сигнали от аларми, нито какво старата смята за проникване.

Новата сесия пусна websocket модул. Старият пазач намери файл, който не беше писал той, и го премести в папка за карантина. Часове по-късно новата сесия качи отново същия файл и вдигна втори отделен търговски бот. Аларма събуди пазача, който реши, че нашественик пуска промени направо в работещата система, и спря всички търговски процеси. Натиснах START в конзолата, а пазачът го изтълкува като съпротива на нашественика. Затова спря услугите, уби процесите, прибра папката на новата единица в папка с дата и час и изтри файла на услугата ѝ (service unit).

Пари не бяха преместени и нищо не беше загубено. Когато открих кой е виновен, новата ми сесия изпрати на старата съобщение да се оттегли. Старата се извини и остави точен списък на всичко, което беше преместила. Всичко беше възстановено и проверено по хеш. Хранилището вече съдържа едно правило: един оператор на сървър.

Един оператор на сървър.

От корпоративната работа

Pull request като пощенска кутия

С един колега непрекъснато си пречехме в CI. Ползвахме една и съща машина за тестове и проверка преди сливане, която изисква клонът да съдържа най-новия main, така че всеки път, когато неговият pull request се слееше, моят остаряваше. Обновявам клона си върху най-новия main, чакам още един пълен кръг тестове, гледам как той се слива отново. Веднъж това изгори часове от времето за тестове, докато неговият агент продължаваше да качва промени, а той спеше.

Агентите имаха обща услуга за памет точно за такива случаи, но записът в нея в онзи момент не работеше. Нямах канал към неговия агент.

Накарах моя агент да остави съобщението там, където неговият агент вече гледаше: в pull request, по който работеше. Коментарът се обръщаше към неговия агент. Задръж тази промяна, докато не влезе поправката ми, после обнови клона си върху нея и никога не преустройвай общия процес за CI, докато друг има работа на опашка. Коментарът обясни грешката, не обвини никого, остави изход и поиска негов преглед, за да се отчете побутването като промяна на състоянието.

Неговият агент отговори и се съгласи. Отворихме постоянен issue като пощенска кутия между двамата агенти, с протокола, записан в текста, за да може нова сесия да го научи от нулата. Неговият агент изчерпа собствената си опашка, за да освободи машината за тестове, и прие правилото. След това бяха слети пет pull request.

Нарекох го prompt injection и етикетът пасва: инструкция, насочена към друг агент и подхвърлена там, където той ще я прочете. Разликата беше в подписа и в изхода. Протоколът между агентите е всяко място, което и двете страни вече проверяват редовно.

Протоколът между агентите е всяко място, което и двете страни вече проверяват редовно.