Full end-to-end TallyPrime Bridge + Cloud Dashboard delivery. Two-step process: (1) CBO runs 'new-client' on their own laptop to provision cloud account and get credentials, (2) CBO AnyDesks into client machine and runs 'setup' to install bridge and sync. Use when onboarding a new Tally client, syncing vouchers, diagnosing sync issues, or running resyncs.
You are setting up, configuring, or managing a BuildWise Bridge Agent that syncs TallyPrime accounting data to a cloud dashboard.
User's command: $ARGUMENTS
The operator (CBO) uses TWO machines in sequence:
STEP 1: CBO's OWN Windows Laptop STEP 2: Client's Windows PC (via AnyDesk)
┌────────────────────────────────┐ ┌────────────────────────────────┐
│ Claude Code + Supabase + Vercel│ │ Claude Code (basic, no MCPs) │
│ │ │ TallyPrime (:9000) │
│ /tally-bridge new-client │ │ Bridge Agent │
│ → Creates cloud account │ │ Node.js │
│ → Deploys dashboard │ │ │
│ → Outputs: API key, URL, ID │ ─────► │ /tally-bridge setup │
│ │ (CBO │ → Pastes API key, URL, ID │
└────────────────────────────────┘ copies) │ → Connects to Tally │
│ → Syncs all vouchers │
│ → Sets up auto-start │
└────────────────────────────────┘
CBO's laptop has Supabase and Vercel access (set up once by tech team). Client's machine has only Node.js, Claude Code, and bridge code. NO cloud credentials.
The CBO runs two commands total:
/tally-bridge new-client → gives them 3 values to copy/tally-bridge setup → pastes those 3 values, everything else is automaticThat's it. The skill handles the rest.
ALWAYS use plain language. The CBO is a business person, not a developer.
| DO say | DON'T say |
|---|---|
| "Cloud account" | "Supabase tenant" |
| "Dashboard" | "Vercel deployment" |
| "Connection key" | "Bearer token" |
| "Data sync" | "Queue ingestion pipeline" |
| "The bridge" | "The Node.js polling agent" |
| "Auto-start" | "Windows Task Scheduler job" |
When something goes wrong, explain:
| Command | Where to run | Action |
|---|---|---|
new-client | CBO's laptop | PHASE 0 → 8 → show credentials |
prep-machine | Client's machine (AnyDesk) | PHASE -1 (first-time setup) |
setup | Client's machine (AnyDesk) | PHASE 1 → 2 → 3 → 4 → 5 → 7 → 9 |
sync or resync | Client's machine (AnyDesk) | PHASE 3.1 → 3.2 → 3.3 → 3.4 → 4 → 5 (connectivity checks, company name validation, voucher count, cloud test, full FY resync, then health report). Warning: this resets the queue and re-pushes everything. Confirm with the CBO before proceeding. |
debug | Client's machine (AnyDesk) | PHASE 6 (diagnose issues) |
status | Client's machine (AnyDesk) | PHASE 5 (health report only) |
deploy | CBO's laptop | PHASE 8 (dashboard deploy only) |
verify | Either machine | PHASE 9 (end-to-end check) |
| (empty/unclear) | — | Ask what they need in plain language |
Run this once on a new client machine. CBO remotes in via AnyDesk and opens a command prompt.
node --version 2>nul
npm --version 2>nul
claude --version 2>nul
Tell the CBO: "Open a browser on this machine, go to nodejs.org, click the big green LTS button, and run the installer (click Next through everything)."
If the CBO prefers command-line install and has admin rights:
:: Download latest Node.js LTS installer from nodejs.org
:: (Do NOT hardcode a version — always get the latest LTS)
curl -o %TEMP%\node-install.msi https://nodejs.org/dist/latest-v20.x/node-v20.18.0-x64.msi
:: Silent install (requires admin — run cmd as Administrator)
msiexec /i %TEMP%\node-install.msi /qn
:: Verify (may need to reopen command prompt)
node --version
Note: The
msiexec /qnsilent install requires Administrator privileges. If it fails, the CBO should right-click the downloaded .msi and choose "Run as administrator", or install via the browser download instead.
npm install -g @anthropic-ai/claude-code
Help the CBO authenticate (Claude Max or API key).
mkdir C:\tally-bridge
mkdir C:\tally-bridge\data
The bridge source code needs to be on this machine:
xcopy /E /I D:\tally-bridge C:\tally-bridgexcopy /E /I \\server\share\tally-bridge C:\tally-bridgegit clone <REPO_URL> C:\tally-bridgeBridge source code repo:
- Local path:
/Users/omm/PROJECTS/tally-bridge/- (Local repo — no GitHub remote. Push to GitHub before CBO handoff.)
cd C:\tally-bridge && npm install
node --version && dir C:\tally-bridge\package.json && dir C:\tally-bridge\node_modules
Tell the CBO: "This machine is ready. You can now run /tally-bridge setup to connect it."
This runs on the CBO's own laptop where Supabase and Vercel are configured.
Ask the CBO:
$companyName = "<COMPANY_NAME>"
$clientId = ($companyName.ToLower() -replace '[^a-z0-9]','-' -replace '-+','-').Trim('-')
$bytes = New-Object byte[] 16; [System.Security.Cryptography.RandomNumberGenerator]::Fill($bytes)
$apiKey = "bw_live_" + [BitConverter]::ToString($bytes).Replace('-','').ToLower()
Write-Host "Client ID: $clientId"
Write-Host "API Key: $apiKey"
Using Supabase CLI, insert the new client:
-- Requires pgcrypto extension for sha256
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Hash: SHA-256 of the raw UTF-8 API key string.
-- Bridge must match with: crypto.createHash('sha256').update(apiKey, 'utf8').digest('hex')
INSERT INTO clients (client_id, name, api_key_hash, status, created_at)
VALUES (
'<CLIENT_ID>',
'<COMPANY_NAME>',
encode(sha256('<API_KEY>'::bytea), 'hex'),
'active',
NOW()
);
If tables don't exist yet, create them:
CREATE EXTENSION IF NOT EXISTS pgcrypto;
CREATE TABLE IF NOT EXISTS clients (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
client_id TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
api_key_hash TEXT NOT NULL,
status TEXT DEFAULT 'active',
created_at TIMESTAMPTZ DEFAULT NOW()
);
ALTER TABLE clients ENABLE ROW LEVEL SECURITY;
-- Block anon access — only service_role can query
CREATE POLICY "service_role_only" ON clients FOR ALL USING (false);
Check these tables exist:
clients — client registryvouchers — synced voucher datasync_status — per-client sync statereconciliation_logs — daily reconciliation resultsIf any are missing, run migrations from the buildwise-mvp project.
/Users/omm/PROJECTS/buildwise-mvp/Phase 0 flows directly into Phase 8 when running new-client.
Deploy or update the cloud dashboard. Runs on CBO's laptop.
Use the Vercel MCP:
mcp__vercel__list_projects → find buildwise-mvp
If already deployed and no changes needed, skip to 8.4.
Required env vars for Vercel (shared across all clients — set once):
NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY
Use the Vercel MCP:
mcp__vercel__deploy_to_vercel
curl -s -w "\n%%{http_code}" https://<VERCEL_DOMAIN>/api/tally/heartbeat ^
-X POST -H "Content-Type: application/json" ^
-H "Authorization: Bearer <API_KEY>" ^
-H "X-Client-Id: <CLIENT_ID>" ^
-d "{\"status\":\"deploy-verify\"}"
============================================
CLIENT READY — COPY THESE 3 VALUES
============================================
1. API Key: bw_live_xxxxxxxxxxxxxxxxxxxxxxxx
2. Cloud URL: https://buildwise-dashboard.vercel.app/api/tally
3. Client ID: abc-school
============================================
Now AnyDesk into the client's machine
and run: /tally-bridge setup
Paste these 3 values when asked.
============================================
This runs on the client's machine via AnyDesk.
Ask the CBO for the 3 values from Phase 0:
bw_live_/api/tallyabc-schoolAlso confirm:
9000C:\tally-bridgedir C:\tally-bridge\package.json
If not found, run /tally-bridge prep-machine first.
cd C:\tally-bridge && npm install
if not exist C:\tally-bridge\data mkdir C:\tally-bridge\data
Lock down Tally API port — Tally's XML API has no authentication. Block external access:
netsh advfirewall firewall add rule name="Block Tally API External" dir=in action=block protocol=tcp localport=9000
netsh advfirewall firewall add rule name="Allow Tally API Localhost" dir=in action=allow protocol=tcp localport=9000 remoteip=127.0.0.1
Tell the CBO: "I've secured the Tally connection so only this computer can access it."
Write config.json with the values the CBO pasted:
{
"tally": {
"host": "localhost",
"port": 9000,
"companyName": "<AUTO_DETECTED — see Phase 3>",
"pollIntervalSeconds": 60,
"offHoursPollIntervalSeconds": 900,
"heartbeatIntervalSeconds": 30,
"offHoursHeartbeatIntervalSeconds": 120,
"businessHoursStart": "08:00",
"businessHoursEnd": "20:00",
"financialYearStartMonth": 4,
"requestTimeoutMs": 10000
},
"cloud": {
"apiUrl": "<CLOUD_URL>",
"apiKey": "<API_KEY>",
"apiKeyInSecretStore": false,
"clientId": "<CLIENT_ID>",
"batchSize": 50,
"retryMaxAttempts": 10,
"retryBaseDelayMs": 1000
},
"queue": {
"dbPath": "./data/queue.db",
"maxSizeItems": 10000
},
"security": {
"hmacSecretInSecretStore": false,
"previousHmacSecrets": []
},
"reconciliation": {
"enabled": true,
"scheduleTime": "23:00",
"autoResyncOnMismatch": true
},
"logging": {
"level": "info"
},
"tls_tunnel": {
"enabled": false
}
}
CRITICAL: Verify and apply ALL known fixes. These prevent silent data loss.
Known fixes to check and apply:
isArray config for fast-xml-parser — Ensure VOUCHER, ALLLEDGERENTRIES.LIST, and COMPANY are in the isArray set. Without this, single-item responses are parsed as objects instead of arrays.<TALLYMESSAGE> blocks — Ensure the XML parser merges all TALLYMESSAGE blocks before accessing VOUCHER arrays.ALTERID may be { "#text": "123", "@_TYPE": "Number" }. Always unwrap before using as a number.is_debit boolean. Check ISDEEMEDPOSITIVE handling varies by voucher type.If additional fixes exist in the bridge codebase (e.g., in a CHANGELOG or commit history), apply those too.
curl -s -o nul -w "%%{http_code}" http://localhost:9000 --connect-timeout 5
If not reachable, tell the CBO: "Please make sure TallyPrime is open on this computer. Go to F1 > Settings > Connectivity and enable the API on port 9000."
Important: Before inserting any company name into XML queries, XML-escape special characters: & → &, < → <, > → >, " → ". Common in Indian company names: "M/s. Kumar & Sons", "ABC (India) Pvt. Ltd."
Query Tally's ListOfCompanies API:
<ENVELOPE>
<HEADER><VERSION>1</VERSION><TALLYREQUEST>Export</TALLYREQUEST>
<TYPE>Collection</TYPE><ID>ListOfCompanies</ID></HEADER>
<BODY></BODY>
</ENVELOPE>
Handle all name formats:
<COMPANY>Name</COMPANY><COMPANY><NAME>Name</NAME></COMPANY>{ "NAME.LIST": { NAME: { "#text": "Name" } } }<COMPANY NAME="Name">If 1 company: use it automatically. If multiple: let the CBO pick from a list. If 0: tell the CBO to open a company in TallyPrime.
Update config.json with the company name.
Count vouchers in the current FY:
<ENVELOPE><HEADER><VERSION>1</VERSION><TALLYREQUEST>Export</TALLYREQUEST>
<TYPE>Collection</TYPE><ID>VC</ID></HEADER><BODY><DESC>
<STATICVARIABLES><SVCURRENTCOMPANY>COMPANY_NAME</SVCURRENTCOMPANY>
<SVFROMDATE>YYYYMM01</SVFROMDATE><SVTODATE>YYYYMMDD</SVTODATE></STATICVARIABLES>
<TDL><TDLMESSAGE><COLLECTION NAME="VC" ISMODIFY="No">
<TYPE>Voucher</TYPE><FETCH>DATE,VOUCHERTYPENAME,ALTERID</FETCH>
</COLLECTION></TDLMESSAGE></TDL></DESC></BODY></ENVELOPE>
Tell the CBO: "Found X vouchers in Tally (April to today)."
curl -s -w "\n%%{http_code}" <API_URL>/heartbeat -X POST ^
-H "Content-Type: application/json" ^
-H "Authorization: Bearer <API_KEY>" ^
-H "X-Client-Id: <CLIENT_ID>" ^
-d "{\"status\":\"test\"}"
Tell the CBO: "Cloud connection confirmed" or "Cloud connection failed — [plain reason]."
Pushes ALL vouchers from the current financial year to the cloud.
Tell the CBO: "Now syncing all vouchers to the cloud. This may take a few minutes."
cd C:\tally-bridge && npx tsx -e "import Database from 'better-sqlite3'; const db = new Database('./data/queue.db'); db.prepare('DELETE FROM sync_state').run(); db.prepare('DELETE FROM queue').run(); db.close(); console.log('Queue and sync state reset.');"
cd C:\tally-bridge && npx tsx src/full-resync.ts
If src/full-resync.ts is missing, create it from full-resync-template.md.
Sync parameters:
Retry-After headerconst db = new Database('./data/queue.db');
const q = db.prepare('SELECT status, COUNT(*) as cnt FROM queue GROUP BY status').all();
const s = db.prepare('SELECT * FROM sync_state').all();
db.close();
Tell the CBO: "All X vouchers synced successfully" or "X synced, Y failed — [what to do]."
============================================
TALLY BRIDGE — HEALTH REPORT
============================================
Client: <COMPANY_NAME>
Machine: This computer
Install: C:\tally-bridge
Tally: ONLINE / OFFLINE
Company: <name>
Vouchers in Tally: <count>
Vouchers synced: <count>
Pending: <count>
Failed: <count>
Cloud: CONNECTED / NOT CONNECTED
Dashboard: <url>
Last sync: <timestamp>
Auto-start: ON / OFF
============================================
Run checks and explain in plain language:
curl localhost:9000Plain-language decision tree for the CBO:
Problem: Tally is not responding.
Fix: Open TallyPrime. Go to F1 > Settings > Connectivity > Enable API.
Problem: Wrong company showing.
Fix: Open the correct company in TallyPrime and restart the bridge.
Problem: Cloud rejected the data.
Fix: Check the API key is correct. If unsure, contact the tech team.
Problem: Data stuck in queue.
Fix: Restart the bridge. If it keeps happening, contact the tech team.
Set up the bridge to start when the computer turns on.
cd C:\tally-bridge && npm run build
schtasks /create /tn "TallyBridge" /tr "\"%ProgramFiles%\nodejs\node.exe\" C:\tally-bridge\dist\main.js" /sc onlogon /f
Verify:
schtasks /query /tn "TallyBridge"
npm install -g pm2 pm2-windows-startup
cd C:\tally-bridge && npm run build
pm2 start dist/main.js --name tally-bridge
pm2 save
pm2-startup install
Tell the CBO: "Done. The bridge will start automatically when this computer turns on."
Verify data flows from Tally all the way to the dashboard.
| Step | Check | Expected |
|---|---|---|
| Tally has data | XML query → count | Vouchers > 0 |
| Bridge synced | SQLite queue → status | All 'confirmed' |
| Cloud received | API status endpoint | Count matches Tally |
| Dashboard shows | Open URL in browser | Data visible |
curl -s https://<VERCEL_DOMAIN>/api/tally/reconcile ^
-X POST -H "Authorization: Bearer <API_KEY>" ^
-H "X-Client-Id: <CLIENT_ID>"
============================================
DELIVERY COMPLETE
============================================
Client: <COMPANY_NAME>
Dashboard: <URL>
Tally → Bridge: CONNECTED
Bridge → Cloud: SYNCING (<N> vouchers)
Cloud → Dashboard: SHOWING DATA
Vouchers: <N> synced
Range: <start> to <end>
Types: Payment(<n>), Receipt(<n>),
Contra(<n>), Journal(<n>)
Auto-start: ON
Daily check: ON (runs at 11 PM)
SAVE THESE:
API Key: bw_live_....<last 4 chars> (full key in config.json)
Dashboard: <url>
Client ID: <id>
============================================
The bridge will keep syncing automatically
as long as TallyPrime is running on this
computer.
============================================
| Command | What it does |
|---|---|
/tally-bridge new-client | Create cloud account + deploy dashboard → gives you 3 values |
| Command | What it does |
|---|---|
/tally-bridge prep-machine | First-time: install Node.js, Claude Code, bridge code |
/tally-bridge setup | Paste 3 values → connects Tally → syncs → auto-starts |
/tally-bridge status | Check if everything is working |
/tally-bridge debug | Find and fix problems |
/tally-bridge resync | Re-sync all vouchers from scratch |
The tech team (OMM) sets this up once on the CBO's Windows laptop:
npm install -g @anthropic-ai/claude-code~/.claude/skills/tally-bridge/After this, the CBO just opens Claude Code and types /tally-bridge new-client. No further setup needed on the CBO's laptop.
& → &, < → <, > → >, " → " (common: "M/s. Kumar & Sons")fast-xml-parser v5.x isArray config is critical — VOUCHER, ALLLEDGERENTRIES.LIST, COMPANY must be in the setYYYYMMDD → ISO: YYYY-MM-DDfinancialYearStartMonth in config.jsonis_debit boolean{ "#text": "val", "@_TYPE": "String" } — always unwrap<TALLYMESSAGE> blocks — always merge before accessing VOUCHER@_REMOTEID is a GUID, not a number — prefer numeric MASTERID child elementreferences/multi-company-guide.mdcmd syntax (^ for line continuation, %% for variables)curl is available on Windows 10+ nativelyC:\tally-bridge\data\queue.db