{"id":44260237,"url":"https://github.com/imbue-ai/latchkey","last_synced_at":"2026-04-10T16:02:38.527Z","repository":{"id":336102890,"uuid":"1135106724","full_name":"imbue-ai/latchkey","owner":"imbue-ai","description":"A command-line tool that injects credentials to curl requests to known public APIs.","archived":false,"fork":false,"pushed_at":"2026-02-27T16:55:50.000Z","size":1095,"stargazers_count":32,"open_issues_count":3,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-27T18:52:04.004Z","etag":null,"topics":["agent-skills","agentic-ai","ai-integration","ai-tools","authentication","credentials","curl","http","third-party-api-integration"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/imbue-ai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-15T16:39:53.000Z","updated_at":"2026-02-27T13:46:17.000Z","dependencies_parsed_at":"2026-02-10T17:01:13.402Z","dependency_job_id":null,"html_url":"https://github.com/imbue-ai/latchkey","commit_stats":null,"previous_names":["imbue-ai/latchkey"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/imbue-ai/latchkey","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imbue-ai%2Flatchkey","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imbue-ai%2Flatchkey/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imbue-ai%2Flatchkey/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imbue-ai%2Flatchkey/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/imbue-ai","download_url":"https://codeload.github.com/imbue-ai/latchkey/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imbue-ai%2Flatchkey/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30175910,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T11:48:51.886Z","status":"ssl_error","status_checked_at":"2026-03-06T11:48:51.460Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-skills","agentic-ai","ai-integration","ai-tools","authentication","credentials","curl","http","third-party-api-integration"],"created_at":"2026-02-10T17:01:05.909Z","updated_at":"2026-04-10T16:02:38.502Z","avatar_url":"https://github.com/imbue-ai.png","language":"TypeScript","funding_links":[],"categories":["Secrets Management \u0026 Isolation"],"sub_categories":[],"readme":"# Latchkey\n\n[![npm](https://img.shields.io/npm/v/latchkey?style=flat-square)](https://npmjs.com/package/latchkey)\n[![CI](https://img.shields.io/github/actions/workflow/status/imbue-ai/latchkey/test.yml?style=flat-square)](https://github.com/imbue-ai/latchkey/actions)\n[![license](https://img.shields.io/npm/l/latchkey?style=flat-square)](LICENSE)\n[![downloads](https://img.shields.io/npm/dm/latchkey?style=flat-square)](https://npmjs.com/package/latchkey)\n\nInject API credentials into local agent requests.\n\n**[Full documentation](https://docs.imbue.com/latchkey)**\n\n## Quick example\n\n```bash\n# User stores the credentials.\nlatchkey auth set slack -H \"Authorization: Bearer xoxb-your-token\"\n\n# Agent makes http calls.\nlatchkey curl -X POST 'https://slack.com/api/conversations.create' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\":\"something-urgent\"}'\n```\n\n## Overview\n\nLatchkey is a command-line tool that injects credentials into curl commands.\n\n- `latchkey services list`\n\t- List third-party services (Slack, Google Workspace, Linear, GitHub, etc.) that are supported out-of-the-box.\n    - (In simple cases, `latchkey services register` can be used to add basic support for a new service at runtime.)\n- `latchkey curl \u003carguments\u003e`\n\t- Automatically inject credentials into your otherwise standard curl calls to HTTP APIs.\n\t- Credentials must already exist (see below).\n- `latchkey auth set \u003cservice_name\u003e \u003ccurl_arguments\u003e`\n\t- Manually store credentials for a service as arbitrary curl arguments.\n- `latchkey auth browser \u003cservice_name\u003e`\n\t- Open a browser login pop-up window and store the resulting API credentials.\n    - This also allows agents to prompt users for credentials.\n    - Only some services support this option.\n\nLatchkey is primarily designed for AI agents. By invoking\nLatchkey, agents can utilize user-provided credentials or prompt\nthe user to authenticate, then continue interacting with HTTP\nAPIs using standard curl syntax. No custom integrations or\nembedded credentials are required.\n\nUnlike OAuth-based flows or typical MCP-style integrations,\nLatchkey does not introduce an intermediary between the agent\nand the service. When the `browser` command is used, requests are made\ndirectly on the user’s behalf, which enables greater flexibility\nat the cost of formal delegation: agents authenticate as the\nuser.\n\nIf a service you need isn’t supported yet, contributions are welcome!\nSee the [development docs](docs/development.md) for details.\n\n## Installation\n\n### Prerequisites\n\n- `curl`, `node` and `npm` need to be present on your system in reasonably recent versions.\n- The `latchkey auth browser` subcommand requires a graphical environment.\n\n### Steps\n\n```bash\nnpm install -g latchkey\n\n# Optionally, if you intend to use `latchkey auth browser`:\nlatchkey ensure-browser\n```\n\nThe `ensure-browser` command discovers and configures a browser\nfor Latchkey to use. It searches for Chrome, Chromium, or Edge\non your system. If none is found, it downloads Chromium via\nPlaywright.\n\n## Agent integrations\n\nWarning: giving AI agents access to your API credentials is\npotentially dangerous, especially when using the `auth browser`\nfeature. They will be able to perform most of the actions you\ncan. Only do this if you're willing to accept the risks.\n\n\n### Using skills.sh\n\n```bash\nnpx skills add imbue-ai/latchkey\n```\n\n### From ClawHub\n\n```bash\nnpx clawhub install latchkey\n```\n\n### As a Pi package\n\n```bash\npi install npm:latchkey\n```\n\n### Manually\n\nThe exact steps will differ depending on the agent. Taking OpenCode as an example:\n\n```bash\nmkdir -p ~/.opencode/skills/latchkey\nlatchkey skill-md \u003e ~/.opencode/skills/latchkey/SKILL.md\n```\n\n### Using the Python `llm` tool\n\nSee [integrations/llm-latchkey/README.md](integrations/llm-latchkey/README.md).\nAlso check out our [llm-webchat](https://github.com/imbue-ai/llm-webchat) web UI that can be used together with Latchkey!\n\n\n## Demo\n\n![Image](https://github.com/user-attachments/assets/953eae6e-35ab-4d64-91f3-98b6843c502d)\n\n\n## Direct usage\n\nLet's revisit the initial example:\n\n```bash\nlatchkey curl -X POST 'https://slack.com/api/conversations.create' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\":\"something-urgent\"}'\n```\n\nNotice that `-H 'Authorization: Bearer ...'` is absent. This is\nbecause Latchkey injects stored credentials automatically. To\nset up credentials for a service (Slack in this example), run:\n\n```bash\nlatchkey auth browser slack\n```\n\nThis opens the browser with a login screen. After you log in, Latchkey extracts\nthe necessary API credentials from the browser session, closes the browser, and\nstores the credentials so that they can be reused.\n\nAlternatively, you can provide credentials manually:\n\n```bash\nlatchkey auth set slack -H \"Authorization: Bearer xoxb-your-token\"\n```\n\n`latchkey curl` passes your arguments straight through to `curl`\nso you can use the same interface you are used to. The return\ncode, stdout and stderr are passed back from curl to the caller\nof `latchkey`.\n\n\n### Self-hosted services\n\nFor services that can be self-hosted, like GitLab, first make Latchkey aware of your service instance:\n\n```bash\nlatchkey services register my-gitlab-instance --service-family=gitlab --base-api-url=\"https://gitlab.example.com/api/v4/\"\n```\n\nThen continue as usual.\n\n```bash\nlatchkey auth set my-gitlab-instance -H \"PRIVATE-TOKEN: \u003ctoken\u003e\"\n\n# Agents can then call the API.\nlatchkey curl https://gitlab.example.com/api/v4/user\n```\n\n\n### Entirely new services\n\nIf you want to use Latchkey with a service that is not in the\nlist of supported built-in services, you can still use the\nmechanism described above to register a new service at runtime:\n\n```bash\nlatchkey services register mastodon --base-api-url=\"https://mastodon.social/api/v1/\"\nlatchkey auth set mastodon -H \"Authorization: Bearer \u003cyour_access_token\u003e\"\n\n# Agents can then call the service:\nlatchkey curl https://mastodon.social/api/v1/timelines/public?limit=2\n```\n\nUser-registered services only support authentication via static curl arguments provided through `latchkey auth set`.\n\n\n### Indirect credentials\n\nSome services can't express their credentials as static curl\narguments. For example:\n\n- AWS requires a signature that changes with each request.\n- Telegram expects bot tokens to be directly part of the URL.\n\nIn similar cases, when supported, you can use the `latchkey auth set-nocurl` command, e.g.\nlike this:\n\n```bash\nlatchkey auth set-nocurl aws \u003caccess-key-id\u003e \u003csecret-access-key\u003e\n```\n\nLatchkey will then modify subsequent `latchkey curl` requests as\nneeded. You can find more information (including the expected\nsignature) by calling `latchkey services info \u003cservice_name\u003e`.\n\n### Remembering API credentials\n\nYour API credentials and browser state are encrypted and stored\nby default under `~/.latchkey`. They are never transmitted\nanywhere beyond the endpoints specified by the actual curl\ncalls.\n\n\n### Inspecting the status of stored credentials\n\nCalling `latchkey services info \u003cservice_name\u003e` will show information\nabout the service, including the credentials status. The\ncredentials status line will show one of:\n\n- `missing`\n- `invalid`\n- `valid`\n- `unknown` (for user-registered services)\n\n### Clearing credentials\n\nRemembered API credentials can expire. The caller of `latchkey\ncurl` will typically notice this because the calls will start returning\nHTTP 401 or 403. To verify that, first call `latchkey services info`, e.g.:\n\n```bash\nlatchkey services info discord\n```\n\nIf the credentials status is `invalid`, it means the Unauthorized/Forbidden\nresponses are caused by invalid or expired credentials rather than insufficient\npermissions. In that case, log in again:\n\n```bash\nlatchkey auth browser discord\n```\n\nOr alternatively:\n\n```bash\nlatchkey auth set discord -H \"Authorization: ...\"\n```\n\n\n### Clearing credentials and logins\n\nIn case you want to remove stored API credentials, use the `auth clear` subcommand.\n\n```bash\nlatchkey auth clear discord\n```\n\nTo clear all stored data (both the credential store and browser state file), run:\n\n```bash\nlatchkey auth clear\n```\n\n\n### Permissions\n\nOptionally, you can specify rules for approving / rejecting\nrequests by creating the `permissions.json` file in the Latchkey\ndirectory (`~/.latchkey/permissions.json`). For example:\n\n```\n{\n  \"rules\": [\n    {\"google-gmail-api\": [\"google-gmail-read-all\"]},\n    {\"slack-api\": [\"slack-read-all\"]}\n  ]\n}\n```\n\nThis would mean that:\n\n- When accessing the Gmail or the Slack API, only read actions are allowed.\n- No requests are allowed to any other domains.\n\nIdeally make the file read-only: `chmod -w ~/.latchkey/permissions.json`.\nFor more details, check out the [Detent docs](https://github.com/imbue-ai/detent).\n\n\n### Other configuration\n\nYou can set these environment variables to override certain\ndefaults:\n\n- `LATCHKEY_DIRECTORY`: path to the directory where Latchkey stores its data (defaults to `~/.latchkey`)\n- `LATCHKEY_CURL`: path to the curl binary\n- `LATCHKEY_KEYRING_SERVICE_NAME`, `LATCHKEY_KEYRING_ACCOUNT_NAME`: identifiers that are used to store the encryption password in your keyring\n- `LATCHKEY_ENCRYPTION_KEY`: override the encryption key, e.g. when a keyring is not available. Example: `export LATCHKEY_ENCRYPTION_KEY=\"$(openssl rand -base64 32)\"`\n- `LATCHKEY_DISABLE_BROWSER`: when set to a non-empty value, disables the browser login flow; commands that would trigger a browser login (`auth browser`, `auth browser-prepare`) will fail with an error instead\n- `LATCHKEY_DISABLE_COUNTING`: when set to a non-empty value, disables daily usage counting.\n- `LATCHKEY_PERMISSIONS_CONFIG`: override the `permissions.json` location.\n\n\n## Disclaimers\n\n- This is still a work in progress.\n- Latchkey has been created with the help of AI-assisted coding tools with careful human curation.\n- Invoking `latchkey auth browser ...` can sometimes have side effects in the form of\n  new API keys being created in your accounts (through browser automation).\n- Using agents for automated access may be prohibited by some services' ToS.\n- Unless `LATCHKEY_DISABLE_COUNTING` is set, once a day, when invoking `latchkey`, a GET request is sent to [goatcounter.com](https://goatcounter.com). We don't store any sort of private information and don't track anything beyond a simple daily count of active users.\n- We reserve the right to change the license of future releases of Latchkey.\n- Latchkey was not tested on Windows.\n\n## Currently supported services\n\nLatchkey currently offers varying levels of support for the\nfollowing services: AWS, Calendly, Discord, Dropbox, Figma, GitHub, GitLab,\nGmail, Google Analytics, Google Calendar, Google Docs, Google Drive, Google Sheets,\nLinear, Mailchimp, Notion, Sentry, Slack, Stripe, Telegram, Yelp, Zoom, and more.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimbue-ai%2Flatchkey","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimbue-ai%2Flatchkey","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimbue-ai%2Flatchkey/lists"}