Skip to main content

Operational guidance coverage

The Guides' recommendations (SHOULD), kept apart from the specification. Upstream: personalagentprotocol.org/docs/guides.

41 entries: 32 implemented, 4 partial, 5 open. Each row is one atomic statement of the upstream text, with the SDK symbols that implement it (Python; TypeScript mirrors them), the tests and shared conformance cases that show it, and its status.

IDSectionLevelRoleRequirementSDK symbolTestsStatus
GUIDE-secrets-01Handling secretsSHOULDbothKeep them out of logs, telemetry, error reports, model context, conversation messages, and URLs.PersonalAgentProtocolErrortest_accounts.py::test_no_error_carries_the_account_token
test_sessions.py::test_session_error_never_includes_remote_error_description
test_conformance.py::test_python_agent_python_company_over_tls
security.refusals-disclose-no-credential
partial: Errors and results are credential-free; logs and traces are not yet covered by a test.
GUIDE-secrets-02Handling secretsSHOULDbothRedact the Authorization, DPoP, and Cookie headers and credential fields before a request reaches a logger or tracer.——open: No logging or tracing hook redacts headers yet.
GUIDE-secrets-03Handling secretsSHOULDcompanySend Cache-Control: no-store on every response that carries a token or code.CompanyService._issue
CompanyService._device
test_conformance.py::test_python_agent_python_company_over_tls
security.token-responses-not-cached
implemented
GUIDE-jwt-01Signing and verifying JWTsSHOULDbothSupport ES256 and RS256, and sign with ES256 when you can. Use RSA keys of at least 2048 bits.JoseSigner
_algorithm
test_crypto.py::test_signs_and_verifies_only_asymmetric_pap_assertions
test_conformance.py::test_python_agent_python_company_over_tls
security.client-assertion-rs256-header-on-ec-key
partial: RSA key size is not checked.
GUIDE-jwt-02Signing and verifying JWTsSHOULDbothReject alg: none and symmetric algorithms such as HS256._algorithm
verify_assertion
test_crypto.py::test_rejects_symmetric_and_none_algorithms
test_conformance.py::test_python_agent_python_company_over_tls
security.client-assertion-alg-none
security.client-assertion-hs256-public-key
security.client-assertion-rs256-header-on-ec-key
security.dpop-alg-none
implemented
GUIDE-jwt-03Signing and verifying JWTsSHOULDcompanyVerify assertions only with keys from the personal agent's verified jwks_uri (4.1). Ignore jku, x5u, and any key embedded in an assertion.verify_assertiontest_conformance.py::test_python_agent_python_company_over_tls
security.client-assertion-embedded-key-ignored
security.session-assertion-wrong-issuer
implemented
GUIDE-jwt-04Signing and verifying JWTsSHOULDcompanyCheck aud, exp, and iat. Allow a small clock skew, such as 30 seconds, and reject assertions that claim a long lifetime.verify_assertiontest_conformance.py::test_python_agent_python_company_over_tls
security.client-assertion-bad-audience
security.client-assertion-audience-array
security.session-assertion-bad-audience
security.session-assertion-clock-skew-tolerated
security.session-assertion-from-the-future
security.session-assertion-expired
security.session-assertion-long-lived
implemented
GUIDE-jwt-05Signing and verifying JWTsSHOULDbothMake each jti at least 128 random bits._opaque_idtest_sessions.py::test_builds_short_lived_session_assertion_claims
test_conformance.py::test_python_agent_python_company_over_tls
security.session-assertion-replay
implemented
GUIDE-keys-01Rotating keysSHOULDpersonal-agentGive every key a kid.JoseSigner
AgentIdentity.jwks
test_identity.py::test_fetches_metadata_and_public_jwksimplemented
GUIDE-keys-02Rotating keysSHOULDcompanyCompanies refetch jwks_uri when they see an unknown kid, with a rate limit so a stream of bad assertions can't trigger a fetch each time.AgentIdentityClient.fetch_jwks
IdentityClientResolver.resolve
test_guidance.py::test_unknown_kid_refetches_the_overlapping_jwks_rate_limited
test_guide_security.py::test_overlapping_jwks_verify_either_key_then_refuse_the_retired_one
test_guide_security.py::test_unknown_kids_refetch_the_set_at_most_once_a_minute
implemented
GUIDE-fetch-01Fetching metadata safelySHOULDbothSet limits: a few redirects at most, a response size such as 100 KB, and a timeout of a few seconds.DiscoveryClient._get_json
AgentIdentityClient._get_json
HttpxDiscoveryTransport.get
test_fixtures.py::test_local_fixture_case
security.discovery-redirect-limit
security.oversized-metadata
security.slow-metadata
security.metadata-not-json
implemented
GUIDE-fetch-02Fetching metadata safelySHOULDbothNever send cookies, tokens, or other credentials on these fetches.HttpxDiscoveryTransport.gettest_discovery.py::test_metadata_fetches_carry_no_cookie_or_credentialimplemented
GUIDE-fetch-03Fetching metadata safelySHOULDbothReject loopback, private, and link-local addresses unless you've configured them on purpose. Check the address you actually connect to, not only the one DNS returned first.PublicUrlSafetyPolicy.assert_safe
PinnedNetworkBackend
HttpxDiscoveryTransport.get
test_discovery.py::test_rejects_private_discovery_address
test_real_sockets.py::test_metadata_connects_to_the_approved_address
test_fuzz.py::test_url_safety_approves_only_https_public_addresses
test_fixtures.py::test_local_fixture_case
security.ssrf-loopback
security.ssrf-private
security.ssrf-link-local-metadata
security.ssrf-ipv6-loopback-and-unique-local
security.ssrf-ipv4-mapped
security.dns-rebinding-mixed-answers
security.dns-rebinding-after-check
security.public-address-allowed
implemented
GUIDE-fetch-04Fetching metadata safelySHOULDbothCache according to HTTP caching headers, within bounds you set, such as at least a minute and at most a day.CacheBounds
cache_lifetime
MetadataCache
DiscoveryClient._get_json
AgentIdentityClient._cached_json
test_guidance.py::test_cache_lifetime_follows_cache_control_within_bounds
test_guidance.py::test_discovery_and_oauth_metadata_are_cached_until_they_expire
test_guidance.py::test_no_store_metadata_is_fetched_every_time
implemented
GUIDE-retry-01RetriesSHOULDpersonal-agentSend an Idempotency-Key on API writes that accept one. Use a random UUID (version 4), and reuse the same key when you retry the same request.——open: ApiClient sends no Idempotency-Key.
GUIDE-retry-02RetriesSHOULDpersonal-agentEach retry needs a new DPoP proof, and a retried token request needs a new assertion.DpopHttpClient.request
SessionClient._request
test_sessions.py::test_retries_once_with_a_fresh_dpop_nonce_and_assertionsimplemented
GUIDE-retry-03RetriesSHOULDpersonal-agentOtherwise, back off exponentially with jitter, cap the delay, and limit the number of attempts.RetryPolicy
DpopHttpClient.request
test_guidance.py::test_retry_policy_honours_retry_after_backs_off_with_jitter_and_caps
test_guidance.py::test_safe_requests_retry_after_retry_after_with_fresh_proofs
implemented
GUIDE-rate-01Rate limitsSHOULDcompanyLimit by client_id, by user, and by session; also send the RateLimit and RateLimit-Policy headers.——open: The reference company does not rate-limit.
GUIDE-rate-02Rate limitsSHOULDpersonal-agentKeep track of limits for each company and share them across your tasks and users.RateLimitBudget
SharedRateLimitBudget
DpopHttpClient.request
test_guidance.py::test_shared_budget_paces_tasks_and_refuses_long_waits
test_guidance.py::test_writes_and_long_pauses_go_back_to_the_caller_and_are_shared
implemented
GUIDE-json-01Transport and JSONSHOULDbothEncode JSON as UTF-8 and reject objects with duplicate member names.loads_stricttest_models.py::test_strict_json_rejects_duplicate_members
test_fixtures.py::test_local_fixture_case
test_fuzz.py::test_strict_json_accepts_every_unique_document_and_refuses_every_duplicate
security.duplicate-json-members
implemented
GUIDE-pa-dpop-01DPoP keys and proofsSHOULDpersonal-agentGenerate a DPoP key pair for each user at each company (4.3).DpopProofRequest
DpopKeys
test_conformance.py::test_python_agent_python_company_over_tlsimplemented
GUIDE-pa-tokens-01Storing tokensSHOULDpersonal-agentRequest Bearer session tokens only for MCP (4.3). Each one is limited to one MCP server by resource.McpBearerAuth
DpopHttpClient.request
test_mcp_and_web.py::test_a_bearer_token_is_refused_everywhere_but_its_mcp_server
test_conformance.py::test_python_agent_python_company_over_tls
lifecycle.mcp-bearer-for-its-url
implemented
GUIDE-pa-tokens-02Storing tokensSHOULDpersonal-agentOn invalid_grant for an account token, delete it and continue signed out.AccountTokenClient.refreshtest_accounts.py::test_invalid_grant_deletes_the_token_and_leaves_the_session_signed_out
test_conformance.py::test_python_agent_python_company_over_tls
implemented
GUIDE-pa-signin-01Choosing how to sign inSHOULDpersonal-agentPrefer direct sign-in, then device sign-in, then mediated sign-in.——open: The SDK offers all three; no helper chooses among them.
GUIDE-pa-browser-01Web browsingSHOULDpersonal-agentUse a separate browser storage context, with its own cookies and local storage, for each session.——open: The browser is a host contribution (pap.browserFormPost); isolation is not checked.
GUIDE-pa-conv-01ConversationsSHOULDpersonal-agentRead events with a long wait, such as 30 seconds, or a stream, rather than many short polls (7.5).ConversationClient.eventstest_conversations.py::test_events_recover_cursor_drain_backlog_and_suppress_duplicatesimplemented
GUIDE-co-consent-01Consent pagesSHOULDcompanyProtect the page against cross-site request forgery, and against framing by other sites with Content-Security-Policy: frame-ancestors.CompanyService._page
CompanyService.consent_decision
CompanyService._operation_page
test_direct_and_api.py::test_the_consent_page_is_never_framed_and_bad_redirects_are_not_followed
test_guide_security.py::test_the_consent_form_is_bound_to_the_browser_that_was_shown_it
test_guide_security.py::test_the_operation_page_refuses_cross_site_and_another_browsers_form
implemented
GUIDE-co-consent-02Consent pagesSHOULDcompanyAccept PKCE with S256 only, and reject plain.CompanyService._authorizetest_direct_and_api.py::test_the_consent_page_is_never_framed_and_bad_redirects_are_not_followedimplemented
GUIDE-co-consent-03Consent pagesSHOULDcompanyReturn iss in every redirect, success or error (MUST, 4.5).CompanyService._redirect_urltest_direct_and_api.py::test_a_denial_reaches_the_agent_as_access_denied_onlyimplemented
GUIDE-co-device-01Device sign-inSHOULDcompanyReturn slow_down to personal agents that poll faster than interval, and keep expires_in short, such as 10 minutes.CompanyService._device_grant
CompanyService._device
test_company_refusals.py::test_polling_too_fast_is_slow_downimplemented
GUIDE-co-mediated-01Mediated sign-inSHOULDcompanyReturn the same failed response for an unknown account and a wrong password, so responses don't reveal whether an account exists.CompanyService._mediatedtest_company_end_to_end.py::test_mediated_sign_in_with_a_one_time_codeimplemented
GUIDE-co-account-01Account settingsSHOULDcompanyOffer a control to disconnect each one. Disconnecting revokes its account tokens and signs out its sessions (4.9).CompanyService.disconnecttest_conformance.py::test_python_agent_python_company_over_tls
lifecycle.disconnect-from-account-settings
implemented
GUIDE-co-conv-01ConversationsSHOULDcompanyOn a stream with nothing to send, send an SSE comment every 15 to 30 seconds, so proxies don't close it (7.6).CompanyService._stream—partial: The stream opens with a comment and ends after the backlog; it does not stay open with keep-alives.
GUIDE-co-conv-02ConversationsSHOULDcompanyWhen a session signs out, close its conversations that used the account, so their account details can't be read signed out (7.11).CompanyService._ownedtest_conformance.py::test_python_agent_python_company_over_tlspartial: A signed-out token gets sign_in_required on them; they are not closed.
GUIDE-co-errors-01Error messagesSHOULDcompanyReturn the same error for "doesn't exist" and "belongs to someone else", as conversation_not_found does (7.13).CompanyService._owned
CompanyService._operation_route
test_conformance.py::test_python_agent_python_company_over_tlsimplemented
GUIDE-ops-pa-01Operations: personal agentsSHOULDpersonal-agentWhen a new revision arrives, show the user what changed before asking them to approve it again.ConfirmOutcome.changedtest_operations.py::test_terms_changed_returns_the_new_revision_and_what_changed
test_conformance.py::test_python_agent_python_company_over_tls
implemented
GUIDE-ops-pa-02Operations: personal agentsSHOULDpersonal-agentIf a term you need to check is missing from terms, ask the user instead.coverstest_operations.py::test_a_standing_permission_that_does_not_cover_it_asks_the_userimplemented
GUIDE-ops-pa-03Operations: personal agentsSHOULDpersonal-agentFor a permission with a limited number of uses, reserve a use before you confirm, so two tasks running at once can't both use the last one. Release the reservation if the company rejects the confirmation.StandingPermissionStore
OperationsClient.confirm
test_operations.py::test_a_refused_confirmation_gives_the_use_back
test_conformance.py::test_python_agent_python_company_over_tls
operations.standing-permission-within-bounds
operations.standing-permission-concurrent-use
implemented
GUIDE-ops-pa-04Operations: personal agentsSHOULDpersonal-agentAfter a confirm times out, read the operation or confirm again with the same revision. Wait for Retry-After between reads.OperationsClient.confirmtest_operations.py::test_a_lost_answer_is_read_back_by_the_same_id_never_assumed_failed
test_conformance.py::test_python_agent_python_company_over_tls
operations.confirm-timeout-recovery
implemented
GUIDE-ops-co-01Operations: companiesSHOULDcompanyWhen you call another system to perform the action, derive its idempotency key from the operation ID.OperationExecutortest_conformance.py::test_python_agent_python_company_over_tlsimplemented
GUIDE-ops-co-02Operations: companiesSHOULDcompanyTo spot the same action coming up in another channel, look for an open operation in the same session or account with the same terms before proposing a new one.CompanyService._proposetest_conformance.py::test_python_agent_python_company_over_tlsimplemented

Conformance case IDs name protocol/fixtures/conformance cases; see the conformance report for their outcome in every language pairing.