agentleFS
chnlichchnlich/charlie-bot/skills/google-oauth/SKILL.md

google-oauth

Skill9 starsChanged 4 days agoMITView on GitHub

Use when a Google integration (Gmail, Docs, Sheets, Drive, Calendar) needs its OAuth client set up, its refresh token obtained again after expiry, or an access token minted at runtime. Use when adding a Google account or choosing among several accounts.

We split this skill into the rules it gives an agent

13 rules. About 0 are common, 8 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈8

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    When one section sets owner, the google section sets owner too.

    line 26
  2. Distinctive:

    When the request names an account, use that account.

    line 70
  3. Distinctive:

    When the request names no account, use the primary account of the asker.

    line 75
  4. Distinctive:

    When the asker owns no account, stop, and say that this host holds no Google account of the asker.

    line 76
  5. Distinctive:

    When the request words match no account, stop and show the account list.

    line 78
  6. Distinctive:

    When the request names no account, also name in the reply the accounts not checked.

    line 80
  7. Very specific:

    Run charliebot google consent-url <name>.

    line 93
  8. Very specific:

    When the google section sets owner, pass --owner with the person name of the account owner.

    line 100
  9. Very specific:

    When Google shows one of these errors, choose a Desktop-app client that admits the account.

    line 116
  10. Very specific:

    Put its client_id and client_secret into the google_account_<name> section.

    line 117
  11. Distinctive:

    Create an OAuth client of type Desktop app.

    line 126
  12. Distinctive:

    Follow Add or Re-Authorize an Account to authorize an account.

    line 127
  13. Distinctive:

    If the GCP project is in Testing mode, the refresh token expires in about seven days.

    line 137

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Google OAuth

charliebot google reads the account table, sends authenticated requests, lists accounts and adds accounts.

Configuration

  • Credentials location: $CHARLIEBOT_HOME/credentials.yaml; the default home is ~/.charliebot.
  • The google section holds the OAuth client and the default account.
  • The default account name is google.name, or default when that key is absent.
  • Each added account uses a google_account_<name> section.
  • Account names match [a-z][a-z0-9-]* and are unique across the table.
  • An added account can hold its own client_id and client_secret pair.
  • An account section can set owner: the person that the account belongs to.
  • The google section belongs to the host owner, the person who runs this CharlieBot.
  • An added account without owner belongs to the owner of the google section.
  • When one section sets owner, the google section sets owner too.
  • On a host with a Discord list, each owner value is a person name from discord.allowed_users.
  • On a host that serves several people, slack.allowed_user_ids lists only the host owner.
  • Each owner has one primary account.
  • The primary account of the host owner is the default account.
  • The primary account of another person is that person's section with primary: true, or that person's only section.
  • google.docs_default_folder_id applies only to the default account.
  • Access tokens are minted at runtime and are not persisted.

Runtime Requests

Send every Google API request through charliebot google request, which mints the account's access token inside its own process:

charliebot google request <METHOD> <URL> [--account <name>] [--data-file <path> | --json <text>] [--header <name:value>]...

The token never appears in a command, in an output, in a run record or in model context. For the default account, omit --account. --json sends the text as the request body with Content-Type: application/json; --data-file reads the body from a file; each --header adds one header. The command prints the response body on stdout.

Exit codeMeaning
0HTTP 2xx; the response body is on stdout.
1Another HTTP status, a network failure, or a token refresh failure, including a pending account.
2Invalid arguments, or an invalid account table in credentials.yaml.
3credentials.yaml cannot be read.

Redirects are not followed: a 3xx answer exits 1 with its status, so an unexpected redirect is visible.

Accounts

A host holds one or more Google accounts. Each account has a short name, unique on the host.

  • The google section of $CHARLIEBOT_HOME/credentials.yaml holds the OAuth client and the default account.
  • Each added account has its own section, google_account_<name>.
  • An added account section may carry its own client_id and client_secret.
  • charliebot google list prints each account's name, mark, status, owner and description.
  • charliebot google list --check adds each account's email address; a pending account keeps its row with an empty address.
  • The mark is default for the default account and primary for the primary account of another person.

Choose the account before each Google API call:

  • When the request names an account, use that account.
  • Match the request words against each account name and description.
  • The asker is the person who sent the request.
  • In a Discord thread, the asker is the person that charliebot discord read gives for the request.
  • Outside Discord threads, the asker is the host owner.
  • When the request names no account, use the primary account of the asker.
  • When the asker owns no account, stop, and say that this host holds no Google account of the asker.
  • In a Discord thread, give email addresses of the asker's accounts only.
  • When the request words match no account, stop and show the account list.
  • Name the account in each reply that carries Google data.
  • When the request names no account, also name in the reply the accounts not checked.
  • Name the target account in each write draft that waits for take off.

Send each request for the chosen account:

charliebot google request <METHOD> <URL> --account <name>

For the default account, omit --account.

Add or Re-Authorize an Account

The account owner gives consent in a browser. Only the owner can do this step.

  1. Run charliebot google consent-url <name>. When you know the email address of the account, add --email <email address>.
  2. Send the URL to the account owner. When the email address is still unknown, ask the owner for it in the same message.
  3. The owner signs in to that account and approves.
  4. The owner copies the full URL from the browser address bar after the redirect to http://localhost.
  5. Run charliebot google add <name> --email <email address> --redirect-url '<redirect URL>' --description '<one line>' [--owner <person>].
  6. Report the email address that add prints.

When the google section sets owner, pass --owner with the person name of the account owner.

add writes the token only when the consenting account has the given email address.

Two consent errors mean that the OAuth client does not admit the account:

  • The error org_internal: the OAuth client accepts only users of its organization.
  • The error access_denied with "The app is currently being tested": the client is in Testing, and the account is not a test user.

A client admits the account when one of these conditions is true:

  • Its project has the Internal user type, and the account belongs to the project's organization.
  • Its project has the External user type and the Production status. An unverified client shows a warning and admits at most 100 new users.
  • Its project has the Testing status and lists the account as a test user.

A Google Workspace administrator can block a client for the accounts of the organization. When Google shows one of these errors, choose a Desktop-app client that admits the account. Put its client_id and client_secret into the google_account_<name> section. Then start again at step 1. Two OAuth clients can carry one app name, and the consent page shows that name. The name alone does not identify the client: compare the client_id values. In the report to the account owner, name the blocking client by its client_id.

Bootstrap / Re-Authorization

  1. In Google Cloud Console, enable the APIs you need (Gmail, Docs, Sheets, Drive, Calendar).
  2. Create an OAuth client of type Desktop app.
  3. Follow Add or Re-Authorize an Account to authorize an account. The consent flow requests these scopes:
https://www.googleapis.com/auth/spreadsheets
https://www.googleapis.com/auth/documents
https://www.googleapis.com/auth/drive.file
https://www.googleapis.com/auth/gmail.readonly
https://www.googleapis.com/auth/calendar.readonly

If the GCP project is in Testing mode, the refresh token expires in about seven days. Publish the OAuth consent screen to Production for non-expiring tokens.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.