CC_DEV/Docs
Docs
The manual, in plain language, written for the coordinator running it, not the engineer who built it.
Overview
Procore-Bot bulk-edits due dates on Procore Action Plan items. You feed it the week’s lookahead: a CSV or an Excel sheet. It reads what’s in Procore today, writes every change it wants to make to a file you can read line by line, and waits. You confirm once. Then it applies the changes, re-checks every item, and logs every write.
It runs on your own computer (or the crew’s always-on box), with your own signed-in Procore session. There are two ways to drive it: this command line, and the web console.
The five stages
- 1 · Preflight
- Checks your file, your session, and your settings before it touches the network.
- 2 · Plan
- Reads what’s in Procore today and writes
change_plan.json, a read-only list of every date it wants to change. - 3 · Review
- You read the plan and confirm once. The only gate, and it’s yours.
- 4 · Apply
- Applies the confirmed plan. Safe to stop and re-run: it never applies the same change twice.
- 5 · Verify
- Re-checks every item and flags anything that doesn’t match what you approved.
What it will never do
- Sign items off as complete, add signatures, or create and delete sections. These are permanently out of scope. Do them in Procore directly.
- Change anything but due dates unless you switch it on. Assignee and plan-item writes (add and delete items) exist in the code but ship switched off; each needs an explicit sign-off flag to activate.
- Store your password. It borrows the session you already signed into (SSO and MFA included) and keeps it on your hardware.
- Move a date without your confirmation. The plan file is the approval; no plan, no writes.
- Model schedule logic. No predecessor locks, no dependency math. If a date is governed by a workflow, use Procore directly.
Procore is a trademark of Procore Technologies, Inc. Procore-Bot is an independent tool built by one project coordinator, not affiliated with or endorsed by Procore.
Getting started
You need three things:
- Python 3.10 or newer, and the
uvpackage manager. - A Procore account with Action Plans Admin permission on the target project.
- A personal desktop. The tool is single-user and single-machine by design.
Install (one-time per machine)
Four commands: get the code, install the dependencies, install the browser it drives. On Windows, launch.cmd walks the same steps for you.
Sign in once
This opens a real Chrome window. Log into Procore with your normal SSO and MFA; when you can see your project list, press Enter in the terminal. The session is saved to your machine, readable by you only. Re-run it only when preflight says it expired, typically every 14-30 days.
First run
The wizard walks the whole cycle interactively (session, file, plan, confirm, apply, verify) and is the easiest way to learn the shape of it.
Weekly runbook
Every lookahead session is the same steps. On a 50-item plan the whole cycle is about ten minutes, most of it your review.
1 · Refresh your sign-in (only when it expired)
2 · Prepare the lookahead file
Build items.csv from the refined lookahead. Action Plan items have no per-item link, so each row is addressed by the plan’s URL plus the item’s exact title as displayed. A row is a due-date edit unless its action column says otherwise.
| Column | Required | What goes there |
|---|---|---|
plan_url | yes | The Action Plan’s full URL: copy it from the address bar. Rows that share a URL are batched together. |
item_title | yes | The item’s title, exactly as displayed in the plan view. |
action | no | What to do with the row: due (default), assign / unassign, add_item / delete_item. |
target_due_date | for due | ISO YYYY-MM-DD, or CLEAR to clear the date. Not accepted on add_item: a create can’t seed a date; set it with a follow-up due row. |
assignee | for assign | The person’s name as it appears in the project directory. Not accepted on add_item; add them with a follow-up assign row. |
section | for add_item | Which existing section the new item lands in. |
notes | no | Why the row exists. Carried into the audit log. |
21/05/2026, May 21, 2026, and two-digit years are rejected at load. On purpose, before anything touches Procore. Authoring in Excel: format the date column as Text, or set its number format to yyyy-mm-dd.
Clearing a date: put CLEAR (any case) in the date column to set an item back to “no date set.” The plan preview shows it as (clear) and the audit row records it. To restore later, apply the original date in a fresh run.
delete_item removes a record from Procore for good. A rollback re-creates it, but under a new ID. Apply asks for a separate acknowledgement whenever a plan contains deletes; you can switch deletes off entirely in the console’s write policy.
Lookahead lives in Excel? A P6 / MS Project export or a hand-kept sheet can feed the bot directly: no intermediate CSV. See Input files.
3 · Preflight
Checks everything cheap before anything expensive: Python, the browser, your session, the file, the URLs, the dates, and every assignee against the project directory, since Procore 422s any assignment to a user who isn’t active there. Fix and re-run until it’s green.
4 · Plan
Reads the current due date for every row, writes change_plan.json, and prints the diff. Plan is read-only: running it changes nothing in Procore. This is your gate; read it like you’d read a submittal.
5 · Apply
Consumes the plan, asks once, then works through it: creates first, then edits, deletes last. Progress prints per item; audit rows are written as it goes.
6 · Verify
Re-fetches every item and reports anything that doesn’t match what you approved. Run it before you call the update done.
CLI reference
Every command you’d actually run, in plain terms. Any of them takes --help for the full flag list.
| Command | What it does | When you’d run it |
|---|---|---|
auth | Opens Chrome so you can sign in; saves the session locally | When preflight says the session expired |
preflight <file> | Checks the file, session, and environment; fails fast | Start of every cycle |
plan <file> -o <plan> | Reads Procore, writes the reviewable plan. Read-only | After the lookahead is refined |
apply <plan> | Executes the confirmed plan, one confirmation up front | After you’ve read the plan |
verify <plan> | Re-checks every item and reports drift | Right after apply |
wizard | All the steps, guided and interactive | First runs, or whenever in doubt |
presets save / run | Saves a recurring run’s flags under a name; runs it | Weekly scopes, e.g. pre-board-walls |
history <plan_url> "<title>" | Every recorded touch on one item, across all runs | “When did this date move, and who moved it?” |
report | Writes a standalone HTML report from the audit log | Evidence for the OAC or the pre-board |
drift-trend | Baseline-vs-actual due-date drift over time | Spotting slip patterns |
digest / aging-digest | Daily activity summary / weekly aging & blockers | The Monday-morning read |
ics <plan> | Exports a change plan as a calendar file | Dropping dates into Outlook |
monitor | Watches a tracker for added rows; prompts before dispatching a preset | Set-and-check automation |
version | Prints bot, Python, and browser versions | Bug reports |
Flags worth knowing: plan
- --allow-missing
- Skip rows whose title isn’t in the plan (template drift) instead of stopping. Skipped rows are marked
errorin the plan. - --shift-working-days N
- Nudge every target date by N working days (Mon-Fri, weekends skipped), for a lookahead whose whole schedule slipped. Add
--shift-section "Title"to scope it. - --sheet · --header-row
- For Excel trackers with scope-specific sheets or preamble rows above the real header.
- --external-schedule-config
- Read a lookahead XLSX directly via a small column map. See Input files.
Flags worth knowing: apply
- --resume --run-id <uuid>
- Continue a stopped run. Items already applied are looked up in the audit log and skipped.
- --reverse
- Roll a run back: swaps current ↔ target for every change and writes a fresh run id.
- --workers N
- Parallel browser workers, one plan per worker at a time.
- --no-confirm
- Skips the confirmation prompt. For saved presets and automation only.
Input files
items.csv is the everyday input. Seven columns (two always required), addressed by plan URL + exact item title; action defaults to a due-date edit. The full column table is in the runbook.
External lookahead (XLSX): a 3-week lookahead exported from P6 / MS Project / Smartsheet, or a hand-kept forecast sheet, consumed directly. A small TOML file maps your column headers to the bot’s fields (plan_url, item_title, target_due_date, optional notes) and names the sheet and header row. Columns are matched by header name, so your column order is free.
change_plan.json is the written plan. Output of plan, input of apply and verify. It carries the run id and every proposed change; the file, not a dialog box, is what you approve.
Need different dates? Run plan again and get a fresh plan and run id. Editing a plan file and resuming is the one way to sneak an unreviewed change past the gate; the bot detects the mismatch (target-drift guard) and stops.
Run reports
Every run leaves a paper trail on disk, and a few commands turn that trail into something you can hand to someone.
What a run leaves behind
- change_plan.json
- The plan exactly as approved, in
~/.procore-bot/runs/<run_id>/. - log.jsonl
- Every event in the run, timestamped, machine-readable.
- resume.sh
- The exact command to continue the run if it was interrupted.
- data.sqlite
- The audit database: every run, every write. See Audit trail.
Show your work
report writes a standalone HTML file from the audit log: counts, timings, and outcomes, accounted for line by line. It opens anywhere; no bot required to read it.
history answers the smaller question (what happened to this item) across every run that ever touched it.
digest and aging-digest summarize activity: a daily read and a weekly aging-and-blockers read. Both print to the terminal, and can post to a Slack webhook if you configure one.
Harvest sidecar
The harvest sidecar exists for one situation: the bot runs on a machine that isn’t the one where you’re signed in (say, the crew’s always-on mini PC) and you’d rather not type your password anywhere new.
A small Chrome extension watches your normal, signed-in Procore tab. On demand (or automatically, if you opt in), it pushes that session (cookies, never credentials) to the bot’s box over an authenticated channel: Cloudflare Access in front, plus a shared secret. Your password and MFA never leave your browser.
- The session lands on hardware you control; nothing sits on the open internet.
- At-rest encryption for the stored session is available as an opt-in.
- A keep-alive loop stretches the session between Mondays; the extension badge counts down to expiry.
- Every push is logged to its own audit table, including whether the Cloudflare identity check passed.
Then you don’t need any of this. procore-bot auth alone is the whole session story.
Audit trail
Every write is remembered in a single SQLite file: ~/.procore-bot/data.sqlite. The log only grows. The bot never edits or deletes a row. Undoing something is a new run (apply --reverse), which writes its own rows and shows up in Procore’s own audit log as its own event.
What’s in it
| Table | What it records |
|---|---|
runs | One row per run: id, when, what scope. |
audit_entries | Every plan / apply / verify touch on an item: who ran it, what changed, the value before and after. Keyed by plan URL + item title. |
apply_intents | The two-phase safety net: a row is written before each write fires and updated after, so a crash mid-write can’t cause a double-apply on resume. |
harvest_events | Every session push through the sidecar, with the identity-check result. |
Looking things up
Schema upgrades are automatic and additive: opening an old database with a new build migrates it in place, and your history stays.
The audit database is the record. If the trail matters to you, back up data.sqlite like any other project document.
Troubleshooting
The short version: almost everything is recoverable with --resume, and nothing the bot does is hidden from the audit trail.
A run stopped partway
Resume with the same run id. Items already applied are looked up in the audit log and skipped. That’s the idempotency contract; resuming is always safe.
Stopped it with Ctrl+C? The bot writes an executable resume.sh into the run folder with the exact command:
Rolling back
Swaps every applied change back (current ↔ target) under a fresh run id, so the rollback is itself on the record.
Common symptoms
| Symptom | Likely cause | Fix |
|---|---|---|
Preflight: session expired | The SSO window lapsed | procore-bot auth |
Preflight: chromium not found | Browser not installed | playwright install chromium |
Apply: target drift detected | The plan changed since the run started | Run a fresh plan; never hand-edit a plan file |
title not found in enumerated plan | Tracker row isn’t in Procore (template drift) | Fix the tracker, or pass --allow-missing to skip it |
Apply: throttled (HTTP 429) | Procore is busy | It backs off on its own; if persistent, set PROCORE_BOT_PAUSE_MS=5000 and resume |
| 3 straight failures at the start of apply | Procore’s UI changed (selector regression) | Refresh selectors (≈30 min), then resume |
Verify: drift on N items | Someone edited between apply and verify | Re-plan and re-apply if the change is intended |
Assign row fails with 422 | Assignee inactive (or missing) in the project directory | Preflight catches this; fix the name or ask the PM to re-activate the user |
| Every item errors, session valid | No Action Plans Admin on that project | Confirm permission with the project admin |
When not to use it
- A single one-off edit: the Procore UI is faster for one item.
- Dates governed by a workflow: predecessor locks, baseline freezes. The bot doesn’t model dependencies.
- Real-time sync from an external schedule: feed it a file instead.