Legal
Privacy policy
What we collect about you, your organisation and your machines, why, who processes it for us, how long we keep it, and how to have it exported or deleted. Written to match what the code does.
Last updated:
1. Who we are and what this policy covers
Skillhook Cloud is operated by Meter App Inc. (“Meter”, “we”, “us”), meterapp.co. This policy explains what we collect when you use the service at https://skillhook.dev: the website, the dashboard, the REST API, the hosted MCP server, the hosted webhook URLs and the link your paired machines hold to us (together, the “service”). It says why we collect it, who processes it for us, how long we keep it and what you can ask of us.
It covers Skillhook Cloud only. skillhook itself, the open-source server that runs on your machines (github.com/MeterApp/skillhook), sends us nothing until you pair it with skillhook cloud connect. Other Meter products have their own policies. Questions go to support@skillhook.dev.
2. What we collect and why
Almost everything we hold is there because your organisation asked us to show it: what your machines report, what webhook senders deliver, what your agents do and what your team changes. We use it to run the dashboard, the API, the MCP server and the alerts; to keep the service secure; to answer support requests; to email you about your account; and, when billing is turned on, to bill your organisation. We collect nothing to advertise to you or to profile you.
Your account
- Your email address, and the name and avatar picture your sign-in provider gives us: an emailed sign-in link, Google or GitHub, where the deployment offers them. From Google and GitHub we request only the standard openid, email and profile scopes.
- When you first sign in we create a profile (your email address and a display name) and a personal organisation named after you.
Organisations, members and invitations
- Each organisation’s name, URL slug, settings (its name and whether it keeps webhook bodies) and plan; who belongs to it and with which role (viewer, member, admin or owner).
- Invitations: the invited address, the role offered, who sent it and when it expires (seven days). The invitation token is stored as a hash; the link is shown to the admin who made it and emailed to the address, and the email names the inviter’s verified address as the person who sent it.
Machines
A machine you pair reports, on every sync, what the dashboard shows:
- Its name, hostname, operating system, architecture, skillhook and Node.js versions, protocol version, its public URL if it has one, when it started and when it last synced.
- Its mode (observe or control) and link state, its queue and running jobs, which runners it has and whether they are ready, its skills with their settings (runner, how they authenticate and whether a secret is set, filters, schedule) and any load errors, its schedules and linked projects.
- Health checks (name, status, detail and a suggested fix), a snapshot of its configuration and statistics (jobs, failures, cost, tokens, durations, deliveries).
What a machine uploads is decided on the machine (cloud.upload_payloads, cloud.upload_artifacts); it redacts headers and scrubs .env values before sending, so the configuration snapshot never carries a secret. The machine’s own token is stored as a hash.
Webhook deliveries
- For each webhook a machine receives, directly or through a hosted URL: the skill, when it arrived, the outcome (accepted, or rejected and why), the HTTP status and code, the sender’s IP address and user agent, the method and path, the content type and size, the job it started, and the request headers, redacted by the machine before it uploads them.
- The body of the webhook, only while your organisation keeps bodies. “Keep webhook bodies” under Settings is on by default. Turn it off and machines are told to stop uploading bodies, nothing that arrives afterwards keeps one, and bodies already held are deleted when their retention window ends (see how long we keep it); write to us to have them deleted sooner.
Jobs
- For each agent job: the skill, trigger, runner and model, status and outcome, failure details, timing, cost and token counts, an excerpt of the result and the structured response, the progress timeline, the question an agent asked a person and the answer given, and who resolved it.
- Live output while someone watches a job, kept for 24 hours.
- Files a machine uploads for a job (transcripts, results, prompts, payloads, responses), in a private storage bucket served through short-lived signed links after a membership check. A payload is withheld when the organisation keeps no webhook bodies.
Hosted webhook URLs
A hosted URL accepts a sender’s webhook for a machine that may be asleep. We keep the request’s method, source IP address, content type and size in the clear, and seal its query string, headers and body with AES-256-GCM until the machine collects them on its next sync, which deletes the sealed copy; a request no machine collects expires after 72 hours. The machine verifies the sender’s signature with its own secret: we never hold webhook secrets. The URL’s key is stored as a hash for lookup, and sealed so members can see the URL again.
Alerts and notification channels
Open and resolved alerts (an agent needs a person, a machine is offline, a job failed, a health check is failing) and the machine, skill or job they are about. Where alerts go (a Slack URL, a webhook URL and its signing secret, an email address) is sealed; the dashboard shows only the host or the address. We record each notification’s delivery and the last error a target returned.
API keys, tokens and codes
Organisation API keys, machine tokens, pairing codes, invitation tokens and hosted-URL keys are stored as HMAC-SHA256 hashes with a server-side pepper, never the value; a key is shown once, when it is made. For a key we also keep its name, prefix, scopes, who created it, when it was last used and when it expires or was revoked.
Commands and sealed secrets
Every action on a machine is a command: its type and arguments, who asked for it, when it was issued, sent and finished, and its result. A result the machine marks sensitive is never stored. When an admin asks a machine to generate a skill’s webhook secret, the machine seals it to a key that never leaves the admin’s browser; we keep the sealed value at most two minutes, hand it over once and delete it, and cannot read it. A command an offline machine does not collect expires after 10 minutes.
The audit log
Every change in an organisation leaves a row: who made it (a person, an API key, a machine or the system, by id and name), what was done and the ids of what it touched. It never holds payloads, results, the text of a problem report or a secret.
Problem reports
A report to the Skillhook team carries its title and description, its kind and severity, what it is about (a machine, job, delivery or skill), the diagnostics the reporter attaches (a machine sends versions, platform, link state, runner readiness and failing checks, scrubbed of .env values and never payloads or logs), who reported it and the contact address for our answer. We email an acknowledgement to that address and a copy to our support inbox, with the reporter as the reply address.
Server logs and request ids
Every request to the API, the MCP server and the agent API gets a request id, returned to the caller and written to our hosting provider’s logs with the route, status and timing, so a request id you quote lets us find exactly what happened. Errors go to Sentry with the exception, the route, the runtime and ids, scrubbed first (see who processes it for us). Request bodies, cookies, query strings and headers other than a short allow-list never leave the service that way.
Billing
When billing is turned on and your organisation chooses a paid plan, Stripe takes the payment. We store the Stripe customer and subscription identifiers, the plan and its status; card numbers never reach us.
3. Who processes it for us
We do not sell personal data. We share it with nobody except the providers below, each of which gets only what its job needs:
- Supabase: database, authentication and file storage, in its US East (us-east-1) region. Everything listed above lives there.
- Vercel: hosting, the serverless functions that run the service and its minute tick, and request logs, in its iad1 region in the United States. It sees the IP address of every request in the ordinary course of serving it.
- AgentMail: transactional email from our support address, support@skillhook.dev: sign-in links, invitations, the alerts you choose to receive by email and problem-report acknowledgements. It holds the addresses and the messages.
- Sentry: error reports. Before an event leaves the service, request bodies, cookies, query strings and most headers are dropped; API keys, tokens, pairing codes, bearer values and other credentials are replaced with “[Filtered]”; hosted-URL keys and invitation tokens are cut from paths; email addresses become “[email]”; and users, host names and local variables are removed. The Sentry project is set not to store IP addresses. Webhook bodies, job results, SKILL.md files and agents’ questions never go there.
- Stripe: payments, when billing is turned on. Stripe’s own privacy policy applies to the details you enter there.
- Google and GitHub: sign-in providers, only if you choose one; they tell us your email address, name and avatar.
The service calls out to nothing else: notifications go only to the public HTTPS targets your admins configured, checked again before each delivery, and never to your machines, which pull from us. We may also disclose data when the law requires it, to protect the service or its users from abuse, or as part of a merger or acquisition, in which case this policy continues to apply to the data transferred.
4. How long we keep it
Most records are bounded by the database itself, on a schedule that runs every minute:
- Raw events from machines: 14 days. They never keep a webhook body.
- Webhook bodies: for the window your plan gives them (7 days on Free, 30 days on Pro, 90 days on Business, up to 365 days under an Enterprise agreement), and 30 days where an organisation has no window set; only while the organisation keeps bodies at all.
- Live job output: 24 hours. Command results that carry content (files, logs, configuration, secret names, skill files): one day. Finished commands: 30 days.
- Health reports: the newest 30 per machine. Resolved alerts: 90 days. Delivered notifications: 30 days.
- Hosted deliveries: the sealed request is deleted when the machine collects it, and after 72 hours at the latest; the record of the delivery (method, source IP address, size, outcome; never the request) goes seven days after it arrived.
- Sealed secrets a machine generated for an admin: two minutes, handed over once. Pairing codes: seven days after they expire. Invitations: valid for seven days.
- Jobs and deliveries (without their bodies), machines, skills, API key records, the audit log and problem reports: for as long as the organisation exists, so its history and statistics stay whole. Revoked keys and disconnected machines stay in the records as such.
- Account and organisation data: until the organisation is deleted at your request, after which we delete it within 30 days, except what we must keep for tax or accounting.
5. What we never do
- Sell personal data, or share it for advertising. There are no advertising trackers or analytics scripts on the site.
- Send webhook payloads, job results, skill files or agents’ questions to a model, ours or anyone’s. They are data: rendered as escaped text, never logged, never attached to an error report. The agents run on your machines, with your own runner subscriptions.
- Train anything on customer data.
- Connect to your machines. Machines pull from us, and run only what their own mode and allow and deny lists permit.
- Hold your webhook secrets. The machine checks every signature itself, including on deliveries that pass through a hosted URL.
6. Security
Traffic to the service is encrypted in transit. At rest, nothing secret rests in plaintext: tokens, keys, pairing codes, invitations and hosted-URL keys are HMAC-SHA256 hashes with a server pepper; hosted-ingress requests, hosted-URL keys, notification targets and webhook signing secrets are sealed with AES-256-GCM; the tables that hold secrets grant nothing to signed-in users. Every table carries the organisation its rows belong to, and row-level security keeps one organisation’s rows from another’s; our tests assert it for every table.
Control mode is shell access. A machine paired with --control runs what the service queues: skills (agents with tools), configuration changes, skill files, restarts, updates. Anyone who can act as a member or admin of its organisation, or who holds a fleet:run or fleet:admin key, can therefore run code on that machine. You choose the mode when you pair, and you narrow it on the machine with cloud.allow_commands and cloud.deny_commands, which we cannot widen.
No system is perfectly secure. If we learn of a breach that affects you, we tell your organisation’s owners without undue delay.
7. Your rights and how to exercise them
Most of what we hold about your organisation is in the dashboard and the API, and admins can read the audit log. You can revoke API keys, disconnect machines, remove notification channels and turn off keeping webhook bodies yourself. For the rest, whatever the law where you live calls them, you can ask us to tell you what we hold about you, to correct it, to export it in a machine-readable form, to delete it along with your account and your organisation, or to stop processing it. Write to support@skillhook.dev from the address on your account; we answer within 30 days.
If you are in the EU or the UK, the GDPR gives you those rights, and you may also complain to your data-protection authority. For your account, Meter decides what is collected and is the controller; for what your organisation’s machines and webhook senders put into the service, your organisation decides and we process it on its instructions. If you live in California, the CCPA gives you the same rights, and the right not to be treated differently for using them; we do not sell or share personal information as the CCPA defines those words.
The data lives in the United States, with Supabase and Vercel. Where the law requires safeguards for sending it there, we rely on the standard contractual clauses in our providers’ data processing terms.
9. Children
The service is a tool for people who run machines and agents and is not directed at children. We do not knowingly collect personal data from anyone under 16. If you believe a child has created an account, email us and we will delete it.
10. Changes to this policy
When we change this policy we update the date at the top of this page and, for changes that materially affect how we use your data, email account holders at least 14 days before the change takes effect. Continuing to use the service after that date means you accept the updated policy.
11. Contact
Privacy questions and requests: support@skillhook.dev. Meter App Inc., meterapp.co. For the rules that govern use of the service, see the terms of use.