Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ assignees: ""

## Environment

- Tool and version: {e.g. ghl-workflow-exporter 1.0.0 — see its manifest.json}
- Tool and version: {e.g. ghl-workflow-tools 1.1.0 — see its manifest.json}
- Browser: {browser_and_version}
- HighLevel app domain: {app.gohighlevel.com or your white-labelled domain — never paste tokens}

Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Repository baseline: per-tool layout, CI manifest validation, CODEOWNERS, issue/PR templates, security policy, AGPL-3.0 license.
- `ghl-workflow-exporter` — first tool in the set: exports every workflow in the current HighLevel sub-account as re-importable JSON, packaged as a deterministic ZIP for version control.
- `ghl-workflow-tools` ("GHL Workflow Backup") — first tool in the set: exports every workflow in the current HighLevel sub-account as re-importable JSON, packaged as a deterministic ZIP for version control, and restores workflows from a backup as new drafts or in-place overwrites (overwriting a published workflow requires an explicit acknowledgement).
- Legion Code Inc. branding across the root and tool READMEs, extension manifest, and popup.

[Unreleased]: https://github.com/legioncodeinc/ghl-toolset/compare/v0.1.0...HEAD
[0.1.0]: https://github.com/legioncodeinc/ghl-toolset/releases/tag/v0.1.0
13 changes: 8 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Guidance for AI coding agents working in this repository. Read this before touch

A **multi-tool set of Chrome extensions for GoHighLevel (HighLevel) sub-accounts** — one focused, standalone extension per facet of an account (workflows today; pipelines, calendars, custom values, etc. as the set grows). It is deliberately **not** a single bulk tool that migrates or dumps everything from a sub-account. Never propose merging tools or adding "modes" to an existing tool; a new facet means a new tool folder.

The first tool is [`ghl-workflow-exporter/`](ghl-workflow-exporter/). The direction: a tool for every facet of the account that can be read through the app's own session.
The first tool is [`ghl-workflow-tools/`](ghl-workflow-tools/) — "GHL Workflow Backup": exports and restores workflows. The direction: a tool for every facet of the account that can be read through the app's own session.

**Positioning:** the project is published for **R&D purposes only** — it rides on undocumented, internal HighLevel endpoints and is not affiliated with HighLevel. Keep that framing in user-facing docs; never imply production support or endorsement.

Expand All @@ -28,9 +28,10 @@ Every tool follows the same shape (the contract is also documented in the root R
ghl-<facet>-<verb>/
manifest.json # MV3; permissions: activeTab, scripting, downloads — nothing else
popup.html/.css # UI shell
popup.js # orchestration: probes tab, drives export loop, builds files, downloads
popup.js # orchestration: probes tab, drives export/import loops, builds files, downloads
agent.js # functions injected into the page's MAIN world
zip.js # dependency-free ZIP writer (STORE method, fixed 1980-01-01 timestamp)
unzip.js # dependency-free ZIP reader (browser DecompressionStream) — only where a tool reads backups back
icons/
README.md # the tool's own docs
```
Expand All @@ -41,7 +42,7 @@ ghl-<facet>-<verb>/

2. **Never read, store, or transmit credentials.** Authentication is borrowed: prefer `window.SHELL_STORE.$http` (the app's axios instance whose interceptor attaches the session token). Fallback: locate the session JWT inside the page's Vuex auth state and use it *only within the page*, never exfiltrate it. This is the design promise of the whole toolset.

3. **Read-only.** Every request a tool makes is a GET. Never add POST/PUT/DELETE calls to a sub-account.
3. **Exports are read-only; writes are explicit and guarded.** Every request an *export* makes is a GET. Write operations (POST/PUT/DELETE) are allowed only in tools whose purpose includes restore/import, and only as explicit, user-initiated actions. The safety rails are non-negotiable: restores default to creating **drafts**; overwriting an existing workflow is opt-in; overwriting a **published** one requires an extra acknowledgement; nothing is ever published automatically. Never add a write that fires as a side effect of an export or probe.

4. **Minimal permissions.** `activeTab`, `scripting`, `downloads` only. No `host_permissions`, no background service worker, no remote code.

Expand All @@ -53,16 +54,18 @@ ghl-<facet>-<verb>/

## GHL API facts (learned, currently load-bearing)

- List workflows: `GET backend.leadconnectorhq.com/workflow/{locationId}/list` with `limit`/`skip` pagination (`limit: 200` per page; stop when `rows.length >= count`).
- List workflows: `GET backend.leadconnectorhq.com/workflow/{locationId}/list` paginated with `limit`/`offset` (`limit: 200` per page; stop when `rows.length >= count`). **Not `skip`** — the endpoint silently ignores it and re-returns page one; also guard against repeated ids when paging.
- Full workflow definition: `GET backend.leadconnectorhq.com/workflow/{locationId}/{workflowId}?includeTriggers=true` — `includeTriggers=true` is what swaps bare metadata for the `{ workflowData, triggers, dependentAssets }` shape the workflow builder's JSON import accepts.
- Restore/import path (mirrors the app's own restore-from-nodes flow): create via `POST .../workflow/{locationId}` (returns `{ id, assetWarnings }`), delete the target's existing triggers, re-create the incoming triggers (ids stripped, `workflowId` and `actions[].workflow_id` rewired), read them back, then `PUT` the action graph with **`isRestoreRequest: true`** and `newTriggers` set.
- The restore `PUT` must carry the **target's current `version`** (optimistic concurrency — a stale number fails with *"Your version is outdated"*), and `timezone` is an enum (`"account"` etc.), not an IANA name; both fail loudly if wrong.
- Raw-fetch fallback headers (when not using `$http`): `Authorization: Bearer <token>`, `channel: APP`, `source: WEB_USER`, `Version: 2021-07-28`.
- Detecting the sub-account: `window.SHELL_STORE.state.locations.currentLocation` (`.id`/`._id`, `.name`), with the URL path `/location/<id>` as a secondary source.
- HighLevel rate-limits bursts per location. Keep the courtesy pause between per-item requests (~120ms) and the retry-with-backoff pattern (3 attempts, 400ms·n) when adding new export loops.
- These are undocumented internal endpoints; they can change without notice. If an export starts failing, suspect the endpoint shape first.

## Adding a new tool

1. Create `ghl-<facet>-<verb>/` at the repo root with the anatomy above (copy `ghl-workflow-exporter` as the starting skeleton).
1. Create `ghl-<facet>-<verb>/` at the repo root with the anatomy above (copy `ghl-workflow-tools` as the starting skeleton).
2. Give it its own `manifest.json`, icons, and README following the existing tool's README structure (Install / Use / What comes out / How it works / Design notes / Limits).
3. Add a row to the tool table in the root `README.md` (move the facet out of the roadmap list).
4. `scripts/validate-manifests.mjs` picks up any `*/manifest.json` automatically — no registration needed.
Expand Down
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# GHL Toolset

**By [Legion Code Inc.](https://github.com/legioncodeinc)**

[![CI](https://img.shields.io/github/actions/workflow/status/legioncodeinc/ghl-toolset/ci.yml?branch=main&label=CI)](https://github.com/legioncodeinc/ghl-toolset/actions/workflows/ci.yml)
[![License](https://img.shields.io/github/license/legioncodeinc/ghl-toolset)](https://github.com/legioncodeinc/ghl-toolset/blob/main/LICENSE)

A growing set of small Chrome extensions that export, back up, and version-control every facet of a GoHighLevel (HighLevel) sub-account — one focused tool per facet, for agencies and operators who keep their sub-account configuration in git.
A growing set of small Chrome extensions that export, back up, restore, and version-control every facet of a GoHighLevel (HighLevel) sub-account — one focused tool per facet, for agencies and operators who keep their sub-account configuration in git.

> **R&D purposes only.** This toolset is built and published for research and development purposes only. The tools talk to undocumented, internal HighLevel endpoints that can change or break without notice, and this project is not affiliated with or endorsed by HighLevel. Verify everything a tool produces before relying on it anywhere real.

Expand All @@ -15,10 +17,10 @@ This is a deliberate design choice: rather than one bulk extension that migrates

The first tool is live:

| Tool | Status | What it does |
| --- | --- | --- |
| [`ghl-workflow-exporter`](./ghl-workflow-exporter/) | Available | Exports every workflow in the current sub-account as re-importable JSON in a ZIP |
| `ghl-*` — pipelines, calendars, custom values, templates, funnels, forms, and the rest of the account | Planned | One focused tool per facet; see [Roadmap](#roadmap) |
| Tool | Extension | Status | What it does |
| --- | --- | --- | --- |
| [`ghl-workflow-tools`](./ghl-workflow-tools/) | GHL Workflow Backup | Available | Exports every workflow in the current sub-account as re-importable JSON in a ZIP, and restores workflows from a backup — as new drafts or in-place overwrites |
| `ghl-*` — pipelines, calendars, custom values, templates, funnels, forms, and the rest of the account | — | Planned | One focused tool per facet; see [Roadmap](#roadmap) |

## Why it exists

Expand All @@ -29,7 +31,7 @@ Bulk export tools that exist are all-or-nothing: they assume you want everything
Every tool in the set follows the same contract, so behavior learned on one transfers to all of them:

- **No credential handling.** Tools borrow the page's own authenticated HTTP client (`window.SHELL_STORE.$http`) inside the tab you are signed into. No token is read, stored, or transmitted by the extension.
- **Read-only.** Every request a tool makes is a GET. Nothing in the sub-account is modified.
- **Exports are read-only.** Every request an export makes is a GET. Writes exist in exactly one place today — the workflow tool's Import tab — where they are always explicit, user-initiated actions: restores land as new **drafts** by default, overwriting a published workflow requires an extra acknowledgement, and nothing is ever published for you.
- **Minimal permissions.** `activeTab`, `scripting`, `downloads`. No host permissions, no background service worker, no remote code.
- **Works on any GHL host.** White-labelled domains included — tools never hardcode `app.gohighlevel.com`.
- **Deterministic output.** Sorted keys, fixed timestamps, and volatile fields (signed URLs, per-user permission metadata) stripped, so an unchanged sub-account re-exports byte-identically and `git status` stays quiet.
Expand All @@ -40,7 +42,7 @@ About a minute, no build step:

1. Open `chrome://extensions`.
2. Turn on **Developer mode** (top right).
3. **Load unpacked** → select the `ghl-workflow-exporter` folder from your clone of this repo.
3. **Load unpacked** → select the `ghl-workflow-tools` folder from your clone of this repo.
4. Open a HighLevel sub-account tab, click the extension icon, hit **Export workflows**.

## Install
Expand All @@ -56,13 +58,13 @@ Then load the folder of the tool you want via `chrome://extensions` → **Load u

## Usage

Each tool has its own README with its exact flow — start with [`ghl-workflow-exporter/README.md`](./ghl-workflow-exporter/README.md). The shared pattern across all of them:
Each tool has its own README with its exact flow — start with [`ghl-workflow-tools/README.md`](./ghl-workflow-tools/README.md). The shared pattern across all of them:

1. Open the sub-account tab you care about (the tool shows which sub-account it detected).
2. Click the tool's icon and run its action.
3. A ZIP lands in your downloads, shaped for unzipping straight into a git repo.
3. An export lands as a ZIP in your downloads, shaped for unzipping straight into a git repo; a restore takes a previous export (`.zip` or loose `.json`) and writes it back — as drafts unless you explicitly overwrite.

The typical workflow-export session produces:
A workflow backup session produces:

```text
legendary-academy-<locationId>/
Expand Down Expand Up @@ -104,9 +106,10 @@ flowchart LR
A -->|deterministic ZIP<br/>zip.js| E[Download]
```

- `popup.js` — orchestration: probes the tab, drives the export loop, builds files.
- `popup.js` — orchestration: probes the tab, drives the export and import loops, builds files.
- `agent.js` — functions injected into the page's MAIN world. They must be fully self-contained (no imports, no closures) because they are serialized and re-parsed in the page.
- `zip.js` — dependency-free ZIP writer with a fixed timestamp, so identical content produces an identical archive.
- `unzip.js` — dependency-free ZIP reader (the browser's own `DecompressionStream`), so backups can be read back without third-party code.

## Development

Expand Down Expand Up @@ -137,3 +140,5 @@ PRs welcome, especially for the roadmap facets above — one tool per PR, follow
## License

GHL Toolset is licensed under the [GNU Affero General Public License v3.0](./LICENSE). Each tool in the set carries the same license.

Copyright (c) 2026 [Legion Code Inc.](https://github.com/legioncodeinc)
4 changes: 4 additions & 0 deletions ghl-workflow-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,7 @@ Re-exporting an unchanged workflow produces a byte-identical file, so

### 1.0.0
- Export every workflow in the current sub-account as a ZIP.

---

By [Legion Code Inc.](https://github.com/legioncodeinc) · part of the [GHL Toolset](https://github.com/legioncodeinc/ghl-toolset) · AGPL-3.0
2 changes: 2 additions & 0 deletions ghl-workflow-tools/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"name": "GHL Workflow Backup",
"version": "1.1.0",
"description": "Exports every workflow in the HighLevel sub-account you are viewing as re-importable JSON, and restores them from a backup file.",
"author": "Legion Code Inc.",
"homepage_url": "https://github.com/legioncodeinc/ghl-toolset",
"permissions": [
"activeTab",
"scripting",
Expand Down
5 changes: 3 additions & 2 deletions ghl-workflow-tools/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>GHL Workflow Exporter</title>
<title>GHL Workflow Backup</title>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<header>
<h1>Workflow Exporter</h1>
<h1>Workflow Backup</h1>
<p id="target" class="muted">Checking this tab&hellip;</p>
</header>

Expand Down Expand Up @@ -58,5 +58,6 @@ <h1>Workflow Exporter</h1>
</section>

<script type="module" src="popup.js"></script>
<p class="muted foot">by <a href="https://github.com/legioncodeinc" target="_blank" rel="noopener">Legion Code Inc.</a></p>
</body>
</html>