What an agent working in the osh-rfp repo (AAC's CVS Oak Street Health RFP record) can reach and when to read it - the keyed database and its recipes, sources/ and the scenario data/ folders, Outlook and SharePoint, Google Drive, Zoho Desk, the GitHub tracker and the Apps Script runner. Load at the start of any osh-rfp session, and before asking Dan whether a file, export or fact is on hand ("do you have the parts export?").
Install
npx skillscat add surreptakos/claude-dotfiles/osh-rfp-access Install via the SkillsCat registry.
osh-rfp access
The osh-rfp sessions have reached the same sources again and again, and Dan has had to re-tell
each new session what it can read. This page lists them: each source, the instrument that reads
it, the questions it answers, and its known traps. Read the source before asking Dan. A
question goes to him only when it needs a ruling or a fact that no source below holds.
This skill ships in a public repo. File ids, account ids, figures and names stay in osh-rfp; this
page tells you where in osh-rfp to find them. The repo's own notes (docs/agents/memory/,record/*/data/sources.csv) outrank this page. When they disagree, follow the note and fix this
skill (aac-skills/osh-rfp-access/ in claude-dotfiles).
Order of reading
- The database (
db/osh-rfp.sqlite, committed: every checkout has it, so never rebuild it to read it;
osh-rfp #181, Dan, October 4, 2026). It holds the keyed tables, a catalog row for every file in the repo
(documents: what the file holds, how it bears on the bid, its relevance, the file that replaced it) and
every file's full text (document_text). Dan, October 5, 2026: "if it's not in the database, it's
irrelevant to the bid." Start withpython3 tools/db-docs.py search <terms>, then open the file it names. - Live state in its own system (Desk, Outlook, Drive, the tracker, the runner) before any
item goes to Dan. If the system shows an item done, record it as done; do not ask about it. - Dan last, only for a ruling or a fact none of the above holds (a subcontractor's headcount,
a rate). A ticket body, an open-items row, a handoff or a README describes a source. It does not
replace the source, so trace a figure back to its script and export before repeating it.
Never open: the sheets and the Airtable values on the never-open list (login information,
PW&EP users, the Smartsheet-to-Zoho linking sheet, the alarm-code database values;record/OSH-RFP-Tasks.md task 24, ids in record/OSH-RFP-H7.md). Never copy an SSN, a date of birth,
an account or routing number, a password or a key into any file.
Sources
| Source | Instrument | Answers | Read before asking Dan |
|---|---|---|---|
Keyed database db/osh-rfp.sqlite (osh-rfp #110, committed since #181) |
Read as checked out. When a source file it is built from changes, python3 tools/build-db.py rebuilds it and the rebuilt file is committed in the same change; tools/verify-all.py runs build-db.py --current and fails a stale or unstaged database (--check rebuilds twice and runs every recipe); queried with sqlite3 or Python sqlite3. The named recipes are in tools/db-recipes.sql, one per -- name: line. docs/db.md lists every table, key and source file; inside the database, _tables gives row counts and _source_files the sha256 of each file loaded |
Which file answers a bid question, and its text (search_documents, bid_documents, tools/db-docs.py search and text). Joins across exports: which sites bill what (rmr_by_service_line, site_rmr), invoices by type, name-only invoices, the Desk tickets for a site (desk_tickets_for_site), one ticket's trail (ticket_trail), the bills for a work order (bills_for_work_order). Keys: site code and street address, invoice number, Desk ticket number, work order number, BILL.com bill id. Every row carries source_file and source_row |
Never edit the database by hand, and never rebuild it just to read it. Every tracked file is hashed into it, so any committed change to any file needs the rebuilt database in the same commit, and a new file needs a row in record/OSH-RFP-Documents.csv first. The keyed tables leave out the part catalog, the item price list, the Info Sheet tabs and the contact, account and comment columns, but every column of those files is in document_text, nothing blanked (Dan, October 5, 2026): search it with tools/db-docs.py, then read the file directly for exact rows |
sources/ exports |
openpyxl / pandas for .xlsx and .xls, the csv module for .csv |
AlarmBiller S4 and S6 exports: sites, systems, customers, active and cancelled RMR, invoices with paid dates, closed and open work orders, technician time, credits, open appointments, the item price list (OSH-S6-Items.xlsx) and the part catalog (OSH-S6-Parts.xlsx). Also the CVS RFP files, the four OSH contracts, BILL memo and note exports, Info Sheet tab copies (sources/infosheet/) and saved Outlook threads (sources/outlook/) |
record/OSH-RFP-S6-Findings-2026-09-28.md says what each S6 export holds; the join-key table is in docs/agents/memory/info-sheet-answers-before-people.md |
Scenario data/ folders |
the csv module (DictReader in, DictWriter out) |
record/OSH-Loss-Scenario/data/, record/OSH-Win-Scenario/data/, record/Books-Reconciliation/: model inputs, open items (open_items.csv), assumptions, Desk staged-parts evidence, and sources.csv, the S-tag register giving every source's location and as-of date |
Figures change only through the scenario scripts; python3 tools/verify-all.py must pass |
| BILL.com pack and Desk pull | billpack/*.csv, record/desk/*.csv; tools/desk_pull.py re-pulls Desk read-only |
Oak Street vendor bills (osh-bills-matched.csv, the owner-ruled exceptions), the Desk ticket-to-site map |
billpack/osh-bills-unclaimed.csv is the org-wide remainder and is not Oak Street |
| Outlook, OneDrive, SharePoint | Microsoft 365 connector: outlook_email_search, sharepoint_search, sharepoint_folder_search, read_resource |
A thread, attachment or workbook a person would otherwise be asked to find; the latest state of an email exchange | Search before asking for a path. Record what you find with its URL or path (name-the-source-location). Dan's OneDrive is drive b!TNJbz91X... (sources/onedrive/README.md): read_resource on file:///<driveId>/<itemId> returns an .xlsx as tab-separated text, about 190,000 characters at most, ending "Output truncated — N more rows" (a large P&L shows its first ~1,800 rows); file:///<driveId>/<folder path> lists a folder; sharepoint_search finds a file by name or content. It never returns a file's bytes, so a byte-exact copy of a workbook comes from Dan's PC, but its values can be read: the chart of accounts and the Financial Report workbook gave every Chase account's digits on October 5, 2026. Search here, Drive and Outlook before saying an original needs Dan |
| Google Drive and Sheets | Drive connector (search_files, read_file_content, download_file_content); the Sheets API through the aac-google-access skill for full tabs |
The OSH Security & Fire Info Sheet (DATABASE tab: per-site vendors, monitoring holder, camera and door counts), the RMR Items workbook's OSH RMR Worksheet tab (OSH list rates, S2), site tabs, checklists, jobs reporting sheets | Ids are in the info-sheet-answers-before-people note, record/OSH-RFP-H7.md and sources.csv. Never copy code, password or network columns |
| Zoho Desk | Zoho Desk connector: searchTickets with ticketNumber, then getTicket, getTicketComments, getTicketConversations by id |
Service department: what happened on a ticket, staged parts (shelf codes WI1 to WI5 in comments), whether an item is closed. AP department: fields the bill intake extracted (vendor, amount, invoice number, BILL bill id, work order number) | Department and account ids are in info-sheet-answers-before-people. Tickets tie to work orders through cf_aac_work_order_number |
| GitHub tracker | gh in the clone (issues on surreptakos/osh-rfp); node tools/tracker-audit.js before trusting it (exit 2 is not a pass) |
Rulings, open ready-for-human and ready-for-agent work, what a session already filed |
Read the board's workflows before filing a ticket about a board setting; settings are live state |
| Apps Script runner | gas CLI from claude-dotfiles (gas run surreptakos/aac-bill-intake billMemosExport or billNotesExport, gas status surreptakos/aac-bill-intake); the gas-deploy skill |
Fresh BILL.com memo and note exports, AP intake state | Read the runner's last verdict before saying a pull "is running"; until a verdict comes back, call it "queued" |
Known traps (each from an osh-rfp memory note)
- Desk ticket number is not the ticket id. People and records cite the ticket number (five
digits, e.g. 48517).getTickettakes the 19-digit internal id and returnsURL_NOT_FOUNDfor a
number. Look the number up withsearchTickets(ticketNumber), then use the returnedid. - Drive downloads arrive as base64.
download_file_contentreturns the file as one base64
string. Decode it to bytes and write it to a file (an.xlsxis a zip) before parsing. Never try to
read the string as text. For a Google-native file passexportMimeType(text/csvfor one sheet),
or useread_file_contentwhen a text rendering is enough.read_file_contentcan truncate a
large file. A truncated read is not the file, so pull the full tab through the Sheets API instead.
Insearch_filesthe query field istitle, notname. - CRLF files.
record/*/out/**andrecord/*/data/**are-text: they check out exactly as
committed, and the csv-module rows in them end in CRLF. Do not normalize them. A Windows clone made
before the rule shows them as modified when their content is unchanged; delete the tracked files andgit checkout --the folders once. Scenario scripts passencoding='utf-8'andnewline='\n'
(newline=''for a csv writer) and print paths with.as_posix(). - A comma inside a CSV cell is written through
csv.writer, never by hand. The verifiers
fail any row whose field count differs from the header's. - Parts on a work order come from three sources: BILL.com bills (bought for the job),
AlarmBiller parts lines (billed to the customer) and Desk comments (staged from stock). - OSH list rates come from S2's OSH RMR Worksheet tab, never from the AlarmBiller item catalog.
- A bare five-digit number in a BILL memo is as often a zip code as a work order. Match on the PO
box or a tagged number ("WO 40949"). - A dated note records a past state. A memory note or comment that says a runner, grant or
ticket was in some state on some date tells you nothing about now, so read the live system again.
Worked example: "do you have the parts export?"
Answer from this page and the database. Do not ask Dan:
Yes.
sources/OSH-S6-Parts.xlsxis the AlarmBiller part catalog, with cost and rate per Part Code;sources/OSH-S6-Items.xlsxis the item price list, by Item Code. No keyed table loads either file; their text
is indocument_text(python3 tools/db-docs.py search parts catalogfinds them), and I read the rows withopenpyxl. The database holds the parts dollars on each invoice
(invoices.parts_amount) and, through thebills_for_work_orderrecipe, the BILL.com bills that name
a work order. For parts used on a particular work order, I also check the AlarmBiller parts lines and
the Desk staged-parts comments (record/OSH-Loss-Scenario/data/desk_staged_parts_2026-09-30.csv).
Then open the file and confirm the row count and columns before quoting either.