agentlinkops 0.6.13 → 0.6.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +2 -2
- package/CHANGELOG.md +25 -2
- package/PACK-ARTIFACT.json +16 -0
- package/PACKS.json +591 -0
- package/README.md +34 -48
- package/cli/adapters/suppliers.js +1 -1
- package/cli/agent-setup.js +101 -17
- package/cli/campaign-bridge.js +325 -0
- package/cli/campaign-outcomes.js +107 -0
- package/cli/catalog.js +45702 -18674
- package/cli/check.js +40 -10
- package/cli/client.js +2 -1
- package/cli/commands.js +17 -8
- package/cli/connection.js +92 -18
- package/cli/contact-adoption.js +91 -0
- package/cli/context.js +13 -2
- package/cli/doctor.js +15 -4
- package/cli/import.js +7 -1
- package/cli/key-store.js +115 -0
- package/cli/ledger.js +1 -0
- package/cli/local-result.js +41 -6
- package/cli/main.js +51 -12
- package/cli/mcp-client.js +2 -2
- package/cli/migration.js +308 -0
- package/cli/prompt.js +25 -0
- package/cli/public-http.js +168 -0
- package/cli/state.js +14 -0
- package/cli/sync.js +1 -1
- package/package.json +7 -8
- package/references/citation-panels.md +2 -0
- package/references/cli.md +2 -2
- package/references/disavow.md +1 -1
- package/references/discovery-handoff.md +1 -1
- package/references/local-crm-draft-handoff.md +1 -1
- package/references/portable-ledger-handoff.md +11 -10
- package/references/recipes/catalog.json +263 -7
- package/references/recipes/command-notes.md +5 -3
- package/references/recipes/internal-link-improvement.md +25 -0
- package/references/recipes/placement-reconciliation.md +53 -1
- package/scripts/portable-handoff.py +17 -4
- package/shared/admission-contract.js +3 -2
- package/shared/admission-report-contract.js +3 -2
- package/shared/analytics-history-contract.js +15 -0
- package/shared/campaign-outcome-contract.js +12 -0
- package/shared/campaign-prospect-contract.js +23 -0
- package/shared/classification-contract.js +54 -0
- package/shared/contact-record-contract.js +27 -0
- package/shared/disavow-contract.js +37 -9
- package/shared/index-observation-contract.js +5 -4
- package/shared/internal-links-contract.js +143 -0
- package/shared/link-category-contract.js +35 -0
- package/shared/link-category.js +138 -0
- package/shared/link-labels.js +26 -0
- package/shared/link-summary-contract.js +17 -0
- package/shared/observation-event.js +1 -1
- package/shared/onboarding.js +20 -0
- package/shared/response-contract.js +38 -5
- package/shared/search-connection-contract.js +2 -1
- package/shared/table-page-contract.js +13 -0
- package/skills/agentlinkops-assets/SKILL-DEPS.json +290 -0
- package/skills/agentlinkops-assets/SKILL.md +3 -1
- package/skills/agentlinkops-assets/agents/openai.yaml +1 -1
- package/skills/agentlinkops-assets/references/portable/references/cli.md +220 -0
- package/skills/agentlinkops-assets/references/portable/references/disavow.md +73 -0
- package/skills/agentlinkops-assets/references/portable/references/reports.md +53 -0
- package/skills/agentlinkops-assets/references/portable/scripts/agentlinkops.py +676 -0
- package/skills/agentlinkops-assets/references/portable/scripts/disavow.py +207 -0
- package/skills/agentlinkops-assets/references/portable/scripts/migrations/001_crm.sql +45 -0
- package/skills/agentlinkops-assets/references/portable/scripts/migrations/002_cloud_events.sql +13 -0
- package/skills/agentlinkops-assets/references/portable/scripts/migrations/003_disavow.sql +20 -0
- package/skills/agentlinkops-assets/references/portable/scripts/migrations/004_placement_costs.sql +2 -0
- package/skills/agentlinkops-assets/references/portable/scripts/report.py +113 -0
- package/skills/agentlinkops-assets/references/portable/templates/campaigns.v1.json +65 -0
- package/skills/agentlinkops-campaigns/SKILL-DEPS.json +336 -0
- package/skills/agentlinkops-campaigns/SKILL.md +7 -5
- package/skills/agentlinkops-campaigns/agents/openai.yaml +1 -1
- package/skills/agentlinkops-campaigns/references/first-campaign.md +31 -0
- package/skills/agentlinkops-campaigns/references/mailbox-campaign.md +46 -0
- package/skills/agentlinkops-campaigns/references/portable/references/cli.md +220 -0
- package/skills/agentlinkops-campaigns/references/portable/references/disavow.md +73 -0
- package/skills/agentlinkops-campaigns/references/portable/references/reports.md +53 -0
- package/skills/agentlinkops-campaigns/references/portable/scripts/agentlinkops.py +676 -0
- package/skills/agentlinkops-campaigns/references/portable/scripts/disavow.py +207 -0
- package/skills/agentlinkops-campaigns/references/portable/scripts/migrations/001_crm.sql +45 -0
- package/skills/agentlinkops-campaigns/references/portable/scripts/migrations/002_cloud_events.sql +13 -0
- package/skills/agentlinkops-campaigns/references/portable/scripts/migrations/003_disavow.sql +20 -0
- package/skills/agentlinkops-campaigns/references/portable/scripts/migrations/004_placement_costs.sql +2 -0
- package/skills/agentlinkops-campaigns/references/portable/scripts/report.py +113 -0
- package/skills/agentlinkops-campaigns/references/portable/templates/campaigns.v1.json +65 -0
- package/skills/agentlinkops-connect/SKILL-DEPS.json +104 -0
- package/skills/agentlinkops-connect/SKILL.md +2 -0
- package/skills/agentlinkops-connect/agents/openai.yaml +1 -1
- package/skills/agentlinkops-connect/references/agentlinkops.md +164 -62
- package/skills/agentlinkops-connect/references/placement-workflows.md +19 -0
- package/skills/agentlinkops-crm/SKILL-DEPS.json +381 -0
- package/skills/agentlinkops-crm/SKILL.md +26 -9
- package/skills/agentlinkops-crm/agents/openai.yaml +1 -1
- package/skills/agentlinkops-crm/references/portable/references/cli.md +220 -0
- package/skills/agentlinkops-crm/references/portable/references/disavow.md +73 -0
- package/skills/agentlinkops-crm/references/portable/references/local-crm-draft-handoff.md +76 -0
- package/skills/agentlinkops-crm/references/portable/references/portable-ledger-handoff.md +51 -0
- package/skills/agentlinkops-crm/references/portable/references/reports.md +53 -0
- package/skills/agentlinkops-crm/references/portable/scripts/agentlinkops.py +676 -0
- package/skills/agentlinkops-crm/references/portable/scripts/disavow.py +207 -0
- package/skills/agentlinkops-crm/references/portable/scripts/migrations/001_crm.sql +45 -0
- package/skills/agentlinkops-crm/references/portable/scripts/migrations/002_cloud_events.sql +13 -0
- package/skills/agentlinkops-crm/references/portable/scripts/migrations/003_disavow.sql +20 -0
- package/skills/agentlinkops-crm/references/portable/scripts/migrations/004_placement_costs.sql +2 -0
- package/skills/agentlinkops-crm/references/portable/scripts/outreach-crm-draft.py +121 -0
- package/skills/agentlinkops-crm/references/portable/scripts/portable-handoff.py +197 -0
- package/skills/agentlinkops-crm/references/portable/scripts/report.py +113 -0
- package/skills/agentlinkops-crm/references/portable/templates/campaigns.v1.json +65 -0
- package/skills/agentlinkops-discovery/SKILL-DEPS.json +301 -0
- package/skills/agentlinkops-discovery/SKILL.md +4 -2
- package/skills/agentlinkops-discovery/references/portable/references/cli.md +220 -0
- package/skills/agentlinkops-discovery/references/portable/references/disavow.md +73 -0
- package/skills/agentlinkops-discovery/references/portable/references/discovery-handoff.md +32 -0
- package/skills/agentlinkops-discovery/references/portable/references/reports.md +53 -0
- package/skills/agentlinkops-discovery/references/portable/scripts/agentlinkops.py +676 -0
- package/skills/agentlinkops-discovery/references/portable/scripts/disavow.py +207 -0
- package/skills/agentlinkops-discovery/references/portable/scripts/migrations/001_crm.sql +45 -0
- package/skills/agentlinkops-discovery/references/portable/scripts/migrations/002_cloud_events.sql +13 -0
- package/skills/agentlinkops-discovery/references/portable/scripts/migrations/003_disavow.sql +20 -0
- package/skills/agentlinkops-discovery/references/portable/scripts/migrations/004_placement_costs.sql +2 -0
- package/skills/agentlinkops-discovery/references/portable/scripts/report.py +113 -0
- package/skills/agentlinkops-discovery/references/portable/templates/campaigns.v1.json +65 -0
- package/skills/agentlinkops-discovery/references/saved-backlink-workflows.md +23 -0
- package/src/competitors/contract.js +17 -1
- package/src/context/site-profile.js +34 -121
- package/src/corpus/acquire.js +68 -32
- package/src/corpus/extract.js +147 -0
- package/src/corpus/frontier.js +151 -0
- package/src/discovery/contract.js +8 -0
- package/src/discovery/import.js +13 -1
- package/src/mentions.js +193 -0
- package/src/page-acquisition/acquire.js +50 -0
- package/src/page-acquisition/bytes.js +138 -0
- package/src/page-acquisition/capture.js +11 -0
- package/src/page-acquisition/contracts.js +67 -0
- package/src/page-acquisition/documents.js +166 -0
- package/src/page-acquisition/http.js +307 -0
- package/src/page-acquisition/policy.js +20 -0
- package/src/page-acquisition/recovery.js +164 -0
- package/src/page-acquisition/render-failure.js +82 -0
- package/src/page-extraction/html.js +359 -0
- package/src/page-extraction/index.js +30 -0
- package/src/page-extraction/metadata.js +16 -0
- package/src/response-shaping.js +4 -3
- package/src/tool-views.js +22 -12
- package/src/verifier/fetch.js +4 -339
- package/src/verifier/index.js +81 -23
- package/src/verifier/page-quality.js +14 -0
- package/src/verifier/parser.js +2 -241
- package/src/verifier/readiness.js +64 -13
- package/src/verifier/render-evidence.js +25 -2
- package/src/verifier/target.js +201 -0
- package/src/verifier/transition.js +18 -3
- package/src/verifier/url.js +31 -0
- package/src/watch-crawlability.js +144 -0
- package/skills/content-defingerprinting/SKILL.md +0 -29
- package/skills/content-defingerprinting/scripts/watermarks/README.md +0 -102
- package/skills/content-defingerprinting/scripts/watermarks/UPSTREAM.json +0 -26
- package/skills/content-defingerprinting/scripts/watermarks/revendor.sh +0 -52
- package/skills/content-defingerprinting/scripts/watermarks/vendor/LICENSE.upstream +0 -21
- package/skills/content-defingerprinting/scripts/watermarks/vendor/clean_text.py +0 -96
- package/skills/content-defingerprinting/scripts/watermarks/vendor/common.py +0 -432
- package/skills/content-defingerprinting/scripts/watermarks/vendor/inspect_text.py +0 -86
- package/skills/content-defingerprinting/scripts/watermarks/vendor/score_stylometry.py +0 -460
- package/skills/content-defingerprinting/scripts/watermarks/vendor/text_unicode.py +0 -651
- package/skills/content-defingerprinting/scripts/watermarks/verify-vendor.py +0 -27
- package/skills/content-defingerprinting/scripts/watermarks/wm-scan.py +0 -212
- package/skills/internal-linking-optimizer/SKILL.md +0 -56
- package/skills/internal-linking-optimizer/references/source-prompt.md +0 -76
- package/skills/pre-publish-review/SKILL.md +0 -179
- package/skills/source-cited-content-builder/SKILL.md +0 -56
- package/skills/source-cited-content-builder/references/source-prompt.md +0 -19
- package/skills/source-cited-humanizer/SKILL.md +0 -20
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Local CRM contract
|
|
2
|
+
|
|
3
|
+
Version 0.2.0; SQLite schema version 4. Python 3.10+ is the only prerequisite.
|
|
4
|
+
Resolve example helper paths from the plugin root for shared references, or from
|
|
5
|
+
the skill directory for a standalone archive's bundled references. Choose a database
|
|
6
|
+
path in the user's working directory, outside the replaceable plugin cache.
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite init --workspace local-example
|
|
10
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite status
|
|
11
|
+
python3 references/portable/scripts/agentlinkops.py templates
|
|
12
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite product upsert --file product.json
|
|
13
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite opportunity list
|
|
14
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite export --format json --output crm-export.json
|
|
15
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite export --format csv --entity placement --output placements.csv
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`init` binds this database to exactly one workspace ID. Use an actual cloud
|
|
19
|
+
workspace ID if cloud sync is planned. For a purely offline CRM, choose a
|
|
20
|
+
stable local name. Workspace and cloud-origin binding cannot be silently
|
|
21
|
+
changed. A separate local database is required for a different workspace.
|
|
22
|
+
|
|
23
|
+
`migrate` creates a SQLite backup before applying pending migrations. It
|
|
24
|
+
refuses unrelated databases, newer schema versions and changed migration
|
|
25
|
+
checksums. Initialization is idempotent for the same workspace. The CLI has
|
|
26
|
+
no destructive reset command. SQLite is not encrypted; rely on the user's
|
|
27
|
+
device security and store the file in an appropriate location.
|
|
28
|
+
|
|
29
|
+
`upsert` reads one object or an atomic array of objects from a file or stdin
|
|
30
|
+
(`--file -`, the default). IDs are explicit, stable strings; updating an
|
|
31
|
+
existing record changes only supplied fields. References must already exist;
|
|
32
|
+
insert product, campaign/contact, opportunity, then activity/placement.
|
|
33
|
+
|
|
34
|
+
| Entity | Required for a new record, plus `id` | Optional editable fields |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| product | `name`, `url` | `audience`, `description`, `target_pages` (URL array), `notes` |
|
|
37
|
+
| campaign | `name`, `type` | `product_id`, `template_version`, `status`, `goal`, `target_url`, `notes` |
|
|
38
|
+
| contact | `publisher_url` | `name`, `email`, `contact_url`, `source_url`, `observed_at`, `confidence`, `notes` |
|
|
39
|
+
| opportunity | `source_url`, `target_url` | `campaign_id`, `contact_id`, `type`, `status`, `evidence` (object), `notes` |
|
|
40
|
+
| activity | `kind`, `occurred_at` | `opportunity_id`, `contact_id`, `campaign_id`, `channel`, `external_message_id`, `outcome`, `notes` |
|
|
41
|
+
| placement | `source_url`, `target_url` | `opportunity_id`, `project_id`, `watch_id`, `status`, `notes`, `cost_amount`, `cost_currency` |
|
|
42
|
+
|
|
43
|
+
Timestamps require ISO 8601 with a timezone. Link fields require HTTP(S) URLs.
|
|
44
|
+
Null clears an optional relationship ID. Passwords, API keys, tokens,
|
|
45
|
+
mailbox credentials and email/message body fields are rejected. Never put
|
|
46
|
+
those values into free-text notes either. Contact confidence describes the
|
|
47
|
+
evidence, not a promise of email delivery.
|
|
48
|
+
|
|
49
|
+
Example `product.json`:
|
|
50
|
+
|
|
51
|
+
```json
|
|
52
|
+
{"id":"product-example","name":"Example Resource","url":"https://example.com/","audience":"Resource-page readers","target_pages":["https://example.com/guide"]}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Example opportunity evidence:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{"id":"opportunity-example","source_url":"https://publisher.example/resources","target_url":"https://example.com/guide","type":"resource_addition","evidence":{"source_url":"https://publisher.example/resources","observed_at":"2026-09-09T12:00:00Z","context":"Relevant resources section; candidate requires browser review."}}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Use `entity list --id ID` to retrieve a specific record. JSON exports preserve
|
|
62
|
+
all fields, raw events, the sync cursor, disavow rules and their source provenance. They are portable data exports,
|
|
63
|
+
not an automatic full-database restore format. CSV exports select one entity
|
|
64
|
+
and prefix possible spreadsheet formulas with `'`; JSON is lossless.
|
|
65
|
+
Export files are created with restrictive permissions and never overwritten.
|
|
66
|
+
For a restorable database backup, use SQLite's backup API or the SQLite CLI
|
|
67
|
+
`.backup` command; do not copy a live database file while a write is running.
|
|
68
|
+
|
|
69
|
+
## Disavow lists and placement reports
|
|
70
|
+
|
|
71
|
+
For user-selected disavow files, read [the disavow contract](disavow.md).
|
|
72
|
+
The `disavow import/upsert/list/export` commands work offline, require an
|
|
73
|
+
explicit URL-prefix property and preserve source provenance. No command
|
|
74
|
+
uploads to Google or chooses rules from automated risk labels.
|
|
75
|
+
|
|
76
|
+
For branded HTML output, read [the report contract](reports.md). The `report`
|
|
77
|
+
command supports a project filter and optional local notes/cost fields. Notes
|
|
78
|
+
and costs are excluded unless explicitly included. Record a placement cost
|
|
79
|
+
as a decimal string paired with an uppercase currency label, for example
|
|
80
|
+
`"cost_amount":"12.50","cost_currency":"USD"`. Clear both fields with null.
|
|
81
|
+
The CLI validates decimal precision and reports each currency separately.
|
|
82
|
+
It does not verify currency labels against a current exchange-rate service.
|
|
83
|
+
|
|
84
|
+
Existing CRM databases require `migrate` before using version 0.2.0. Schema
|
|
85
|
+
versions 3 and 4 add disavow provenance tables and optional placement cost
|
|
86
|
+
fields. Existing placements, notes, event history and workspace bindings are
|
|
87
|
+
preserved; the helper creates a restorable database backup before upgrading.
|
|
88
|
+
|
|
89
|
+
## Connect the ledger CLI to an existing project
|
|
90
|
+
|
|
91
|
+
Local ledger commands work without an account. Cloud sync uses a separate scoped
|
|
92
|
+
API key. MCP OAuth credentials stay in the MCP client and cannot authorize REST.
|
|
93
|
+
|
|
94
|
+
1. Open the invited account's workspace at `https://app.agentlinkops.com/app`.
|
|
95
|
+
An owner or admin selects **Agent access > Create API key**. Choose the
|
|
96
|
+
existing project and the scopes `projects:read`, `watches:read`,
|
|
97
|
+
`watches:write`, `events:read`, and `exports:create`.
|
|
98
|
+
2. Save the once-shown credential in the user's secret store. Supply it through
|
|
99
|
+
`AGENTLINKOPS_API_KEY` in the CLI process environment. The ledger CLI also accepts
|
|
100
|
+
`AGENTLINKOPS_TOKEN`; if both are set, they must agree. The `LINKTRAIL_` spellings are
|
|
101
|
+
still read, with a one-line warning, during the pilot compatibility window. Never paste credentials
|
|
102
|
+
into chat, command arguments, or ledger files.
|
|
103
|
+
3. Run the installed CLI from the directory containing the existing `.agentlinkops/` (or `.linktrail/`)
|
|
104
|
+
ledger. Replace the script path and IDs below with the installed package path
|
|
105
|
+
and IDs returned by `get_workspace` and `list_projects`.
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
node /path/to/installed/plugin/cli/agentlinkops.mjs connect --origin https://app.agentlinkops.com --workspace WORKSPACE_ID --project-id PROJECT_ID --selection selected-links.json
|
|
109
|
+
node /path/to/installed/plugin/cli/agentlinkops.mjs sync --dry-run
|
|
110
|
+
node /path/to/installed/plugin/cli/agentlinkops.mjs sync --pull-only
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`selected-links.json` contains an array of existing ledger IDs, such as
|
|
114
|
+
`["local-placement-1", "local-placement-2"]`. A mapping file with
|
|
115
|
+
`entries: [{"local_id": "local-placement-1"}]` also works. Save an explicit
|
|
116
|
+
selection when only part of an existing ledger belongs in cloud monitoring.
|
|
117
|
+
|
|
118
|
+
`connect` verifies workspace identity, project access and required scopes through
|
|
119
|
+
read-only REST calls. It saves connection metadata and the selection in
|
|
120
|
+
`.agentlinkops/config.json`, without saving the credential or creating cloud records.
|
|
121
|
+
`sync --dry-run` reads local files only and previews uploads. `sync --pull-only`
|
|
122
|
+
retrieves cloud history without creating watches. After reviewing the plan, run
|
|
123
|
+
`sync` when the user has authorized its proposed monitoring. A saved selection
|
|
124
|
+
limits uploads; without one, sync selects expected or earned entries and pauses mapped retired
|
|
125
|
+
entries. Wanted entries require `--include-wanted`.
|
|
126
|
+
|
|
127
|
+
The cloud stores normalized source URLs: `https://example.com` becomes
|
|
128
|
+
`https://example.com/`. Send the ledger ID as `localReference` and join returned
|
|
129
|
+
rows using `local_reference`. Raw URL string equality can miss an existing watch.
|
|
130
|
+
Copy watch IDs from tool results without shortening them.
|
|
131
|
+
|
|
132
|
+
The Python CRM helper has its own environment settings and workspace binding,
|
|
133
|
+
described in [optional cloud sync](#optional-cloud-sync). Ledger `connect` does
|
|
134
|
+
not configure that helper. If account access or permission to create a credential
|
|
135
|
+
is unavailable, use the existing MCP connection for cloud work and keep local
|
|
136
|
+
records intact.
|
|
137
|
+
|
|
138
|
+
## Optional cloud sync
|
|
139
|
+
|
|
140
|
+
Set `AGENTLINKOPS_API_URL` to the actual service origin and
|
|
141
|
+
`AGENTLINKOPS_API_KEY` using the shell's existing secure environment mechanism.
|
|
142
|
+
Create the scoped credential in **Agent access > Create API key** as described
|
|
143
|
+
[above](#connect-the-ledger-cli-to-an-existing-project). For this read-only event
|
|
144
|
+
sync, select `events:read` and the projects whose events the CRM should receive.
|
|
145
|
+
This toolkit does not bundle credentials or create an account. Never paste keys into chat or command-line arguments.
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite sync --limit 100 --max-pages 100
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The client requests `GET /v1/events?limit=100&cursor=...`. Production origins
|
|
152
|
+
require HTTPS. Loopback HTTP is supported for local development. Redirects
|
|
153
|
+
are rejected so bearer credentials never follow an endpoint redirect.
|
|
154
|
+
Requests time out after 30 seconds and responses are limited to 4 MiB.
|
|
155
|
+
|
|
156
|
+
Expected response:
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"workspace_id": "workspace-example",
|
|
161
|
+
"events": [{
|
|
162
|
+
"id": "event-example", "workspace_id": "workspace-example",
|
|
163
|
+
"cursor": "opaque-cursor", "type": "watch.state_changed",
|
|
164
|
+
"project_id": "project-example", "watch_id": "watch-example",
|
|
165
|
+
"created_at": "2026-09-09T12:00:00Z",
|
|
166
|
+
"data": {
|
|
167
|
+
"before": {"state": "unknown"},
|
|
168
|
+
"after": {"state": "present", "source_url": "https://publisher.example/resources", "target_url": "https://example.com/guide"},
|
|
169
|
+
"observation_id": "observation-example", "evidence_key": null
|
|
170
|
+
}
|
|
171
|
+
}],
|
|
172
|
+
"next_cursor": "opaque-cursor", "has_more": false
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Each page commits new events, placement overlays and its cursor in one
|
|
177
|
+
transaction. Duplicate event IDs are ignored only when the payload is
|
|
178
|
+
identical. A changed payload, malformed event or mismatched workspace rolls
|
|
179
|
+
back the entire page. Earlier successful pages remain committed if a later
|
|
180
|
+
page fails; rerunning resumes at the last committed cursor. Two concurrent
|
|
181
|
+
syncs detect a cursor conflict and require a retry.
|
|
182
|
+
|
|
183
|
+
Events update placement `cloud_state`, `cloud_observed_at` and
|
|
184
|
+
`cloud_event_id`. Existing local `status`, `notes` and opportunity links are
|
|
185
|
+
preserved. URLs follow the cloud watch snapshot. A previously unseen watch
|
|
186
|
+
creates `id: cloud:<watch_id>` only when the snapshot supplies source and
|
|
187
|
+
destination URLs. Partial snapshots without a URL pair and unknown event types are retained in the event
|
|
188
|
+
feed for later interpretation; they do not fabricate a placement.
|
|
189
|
+
|
|
190
|
+
HTTP 410 reports `CURSOR_EXPIRED` and does not advance the cursor. Preserve
|
|
191
|
+
the database and export first; obtain a current watch snapshot and recover
|
|
192
|
+
into a separate database before replaying retained events. Automated snapshot
|
|
193
|
+
recovery is not implemented in this version. Removing the cursor alone would
|
|
194
|
+
hide a history gap and is not a supported recovery procedure.
|
|
195
|
+
|
|
196
|
+
All success output is JSON except requested CSV export. Errors are JSON on
|
|
197
|
+
stderr with nonzero exit status. HTTP response bodies and credential values
|
|
198
|
+
are never included in errors. Local operation has no telemetry.
|
|
199
|
+
|
|
200
|
+
## Writer-lock recovery candidate
|
|
201
|
+
|
|
202
|
+
The maintained development source adds verified-owner recovery for `sync.lock`
|
|
203
|
+
and the ledger's secondary writer lock. This source acceptance is separate from
|
|
204
|
+
an installed release and hosted/client acceptance. A persistent OS advisory gate
|
|
205
|
+
serializes cooperating writers; valid same-user/same-boot metadata for a departed
|
|
206
|
+
writer can be recovered. Marker age alone never authorizes removal. Live, reused,
|
|
207
|
+
legacy empty, malformed or unverifiable markers are preserved with a refusal.
|
|
208
|
+
|
|
209
|
+
Keep the local ledger, mirror and state files. Read-only `status`/`report` remain
|
|
210
|
+
useful while writer ownership is unresolved. Inspect a copy; do not delete a live
|
|
211
|
+
lock or signal a process you did not create. An uncertain cloud request still
|
|
212
|
+
needs its original operation/readback before any write is retried; releasing a
|
|
213
|
+
local lock does not prove the remote request failed.
|
|
214
|
+
|
|
215
|
+
The candidate uses pinned prebuilt native assets for Darwin/Linux, with no compiler
|
|
216
|
+
fallback in the package build. Actual crash and relocated-package acceptance is
|
|
217
|
+
recorded for Darwin arm64; other architectures, Windows, musl and network-file
|
|
218
|
+
systems require separate proof. Unsupported/native-unavailable writers fail
|
|
219
|
+
closed with actionable setup diagnostics. Native lock acceptance does not enable
|
|
220
|
+
Darwin OAuth custody or establish customer credentials/grants.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# User-managed disavow lists
|
|
2
|
+
|
|
3
|
+
This is an offline record/file tool. It does not evaluate whether a link
|
|
4
|
+
should be disavowed, connect to Search Console, or upload a file. Record the
|
|
5
|
+
user's explicit choices and their provenance.
|
|
6
|
+
|
|
7
|
+
Google's documented file format uses one page URL or `domain:hostname` per
|
|
8
|
+
line, UTF-8 or ASCII `.txt` files, and `#` comment lines. The limits are 2,048
|
|
9
|
+
characters per URL, 100,000 lines including comments/blanks, and 2 MB. Domain
|
|
10
|
+
and subdomain rules are supported; a path prefix is not a domain-wide rule.
|
|
11
|
+
The tool does not support Search Console Domain properties. Uploading a new
|
|
12
|
+
list replaces the list for the selected property; local merging here does
|
|
13
|
+
not establish what Google currently holds. Google says most sites do not
|
|
14
|
+
need disavowals. [Official format and usage guidance](https://support.google.com/webmasters/answer/2648487?hl=en),
|
|
15
|
+
checked September 9, 2026.
|
|
16
|
+
|
|
17
|
+
## Commands
|
|
18
|
+
|
|
19
|
+
Resolve example helper paths from the plugin root for shared references, or from the skill directory for a standalone archive's bundled references. Keep the database outside the installation directory:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite migrate
|
|
23
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite disavow import --property https://my-product.com/ --source "User-reviewed existing list" --file existing-list.txt
|
|
24
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite disavow list --property https://my-product.com/
|
|
25
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite disavow export --property https://my-product.com/ --output reviewed-disavow.txt
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Every command requires the exact URL-prefix property. HTTP and HTTPS remain
|
|
29
|
+
separate; a subdomain or path prefix remains separate from its parent. The
|
|
30
|
+
helper records this local scope; it does not verify property ownership.
|
|
31
|
+
|
|
32
|
+
Imports merge rules transactionally. Any invalid line rejects the entire
|
|
33
|
+
file with no new rules or source record. Duplicates reuse stable rule IDs.
|
|
34
|
+
Each source retains its label, original text and SHA-256; provenance records
|
|
35
|
+
the original line, line number and associated comments. Reimporting identical
|
|
36
|
+
content under the same source label is idempotent. A new source label adds
|
|
37
|
+
provenance without duplicating the rule. Imports never overwrite local notes
|
|
38
|
+
or reactivate a rule the user disabled.
|
|
39
|
+
|
|
40
|
+
To add or explicitly change a rule, prepare `rule.json` and run:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite disavow upsert --property https://my-product.com/ --source "User decision after review" --file rule.json
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
{"kind":"domain","value":"publisher.example","active":false,"notes":"User removed this rule after reviewing the source."}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`kind` is `domain` or `url`. `active` defaults to the existing value, or true
|
|
51
|
+
for a new rule. Omitted notes are preserved. Deactivation is reversible and
|
|
52
|
+
retains provenance; there is no destructive delete command.
|
|
53
|
+
|
|
54
|
+
Domain normalization changes case and a terminal DNS dot only. Hostnames
|
|
55
|
+
must be ASCII or already Punycode; the helper does not guess IDN conversion.
|
|
56
|
+
URLs preserve path case, query strings and fragments. A path ending in `/`
|
|
57
|
+
is still one exact page URL; wildcard patterns are rejected. URL credentials
|
|
58
|
+
and malformed domains are rejected. UTF-8 paths, LF/CRLF and an optional UTF-8
|
|
59
|
+
BOM are accepted. Original source text remains available in the full JSON
|
|
60
|
+
CRM export.
|
|
61
|
+
|
|
62
|
+
`.txt` exports contain active rules for one property, sorted by rule kind and
|
|
63
|
+
value with stable header comments. They omit timestamps and private notes,
|
|
64
|
+
so unchanged rules produce identical bytes. The export is checked against
|
|
65
|
+
the documented line limit and a conservative 2,000,000-byte ceiling, and never
|
|
66
|
+
overwrites an existing file. The same byte ceiling applies to imports.
|
|
67
|
+
Without `--output`, it writes the same text to stdout. The local list can be
|
|
68
|
+
empty; an empty export is not evidence that a Google-side list was cleared.
|
|
69
|
+
|
|
70
|
+
`disavow list --active-only` filters the view. The general `export` command
|
|
71
|
+
includes all disavow rules, sources and provenance in the local JSON backup.
|
|
72
|
+
No monitoring result, authority metric or contact inspection automatically
|
|
73
|
+
creates a rule.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# From research to a checked shortlist
|
|
2
|
+
|
|
3
|
+
Keep research notes beside the user's project. The graph release, source retrieval date and qualification explain why a page is on the shortlist. They do not establish a live backlink.
|
|
4
|
+
|
|
5
|
+
Use `agentlinkops skill --list` to see the installed set and `agentlinkops skill agentlinkops-discovery` to read the research workflow. `agentlinkops skill` still prints the connection and evidence reference.
|
|
6
|
+
|
|
7
|
+
Create a CSV with exact source and target pages:
|
|
8
|
+
|
|
9
|
+
```csv
|
|
10
|
+
source_url,target_url
|
|
11
|
+
https://publisher.example.org/resources,https://example.com/guide
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Preview normalization before writing:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
agentlinkops import shortlist.csv --target example.com --from csv --map source=source_url,target=target_url
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The preview is not a live check or a watch. Inspect accepted and rejected rows. For a selected opportunity that has not been earned, initialize a local ledger when needed and add it as wanted:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
agentlinkops init
|
|
24
|
+
agentlinkops add --source https://publisher.example.org/resources --target https://example.com/guide --intent wanted --note "Research candidate; link not yet earned"
|
|
25
|
+
agentlinkops check --all --json
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The local check includes wanted entries; `--all` rechecks the selected rows even if their cadence is not yet due. Keep observed absence separate from unknown access failures. Once the user has an earned placement, record the exact source/target pair as expected and retain the observation date and evidence.
|
|
29
|
+
|
|
30
|
+
For an already connected workspace, `agentlinkops tools monitoring` and `agentlinkops describe monitor_link` expose the current hosted contract. Inspect project IDs and usage first. Enroll selected source/target pairs only when recurring monitoring is within the user's request; record the returned watch IDs. A successful import or local check alone does not create a recurring hosted job.
|
|
31
|
+
|
|
32
|
+
Use the customer's brief and evidence to decide the next campaign step. For additional guidance, select `agentlinkops agent setup --skill agentlinkops-campaigns` and read that installed skill. The [CRM reference](cli.md) covers optional records when the user needs contacts and activities beside the ledger. Outreach stays in the user's chosen tool and requires their instruction.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Branded HTML placement reports
|
|
2
|
+
|
|
3
|
+
Reports are generated entirely from the local CRM. They make no network
|
|
4
|
+
requests, run no additional checks, and do not imply broader backlink-index
|
|
5
|
+
coverage. The output is standalone HTML with embedded styles and print
|
|
6
|
+
styling; it is not a generated PDF.
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite report --project project-id --brand "My Agency" --title "Placement monitoring report" --output placements.html
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Omit `--project` only when the requested report covers every local placement.
|
|
13
|
+
By default, a report includes source/destination URLs, cloud-observed state,
|
|
14
|
+
observation timestamp, report timestamp and aggregate placement counts.
|
|
15
|
+
It excludes local notes, local costs, contacts, outreach activity, credentials,
|
|
16
|
+
disavow rules, workspace IDs and raw event payloads. URLs are the selected
|
|
17
|
+
records' actual URLs; review the selection before sharing the file.
|
|
18
|
+
|
|
19
|
+
`--include-notes` and `--include-costs` explicitly add those private local
|
|
20
|
+
fields. Use these only when the user requests that content. Included cost
|
|
21
|
+
totals are calculated separately per currency without exchange rates.
|
|
22
|
+
Local CRM status is not substituted for a verified cloud observation.
|
|
23
|
+
|
|
24
|
+
Record a cost with an ordinary partial placement upsert:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{"id":"placement-id","cost_amount":"12.50","cost_currency":"USD"}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Amounts are nonnegative decimal strings with at most six decimal places,
|
|
31
|
+
not JSON floating-point numbers. Both amount and currency are required for
|
|
32
|
+
a newly recorded cost. The currency is an uppercase three-letter label;
|
|
33
|
+
the helper does not perform a current currency-directory lookup. Updating
|
|
34
|
+
other fields or synchronizing cloud events preserves local costs. Set both
|
|
35
|
+
cost fields to null to clear a cost explicitly.
|
|
36
|
+
|
|
37
|
+
The generator escapes all text/attributes and creates clickable links only
|
|
38
|
+
for HTTP(S) URLs without credentials. It loads no external scripts, fonts,
|
|
39
|
+
logos or tracking pixels. The title and brand are user-selected text labels.
|
|
40
|
+
Local notes remain escaped text, even if they contain HTML.
|
|
41
|
+
|
|
42
|
+
Rows have a stable ordering. Supply a fixed `--generated-at` ISO 8601
|
|
43
|
+
timestamp to reproduce identical output from the same data and options:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
python3 references/portable/scripts/agentlinkops.py --db ./agentlinkops.sqlite report --title "Placement report" --generated-at 2026-09-09T14:00:00Z --output reproducible.html
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Otherwise the timestamp is the current time. Coverage reports the range of
|
|
50
|
+
stored observation times separately from report generation. Unknown and
|
|
51
|
+
unobserved states remain distinct from confirmed loss. Existing output files
|
|
52
|
+
are never overwritten. Browser printing, PDF generation and automated report
|
|
53
|
+
delivery are separate capabilities and are not performed by this helper.
|