Welcome to Housecarl. This guide walks through sign-up, CLI setup, a simple policy, and a live authorization check.
By the end of this guide, you'll have:
Head over to housecarl.cloud and sign up. You have two options:
When you create your tenant, Housecarl automatically sets up:
For details on what gets created, see Tenant Management.
The housectl CLI is your primary tool for managing Housecarl and testing authorization.
Prebuilt GitHub release binaries are not currently published. Build housectl from source:
git clone https://github.com/upside-down-research/code.git
cd code
# Build with Bazel
./bzsh build //housecarl:housectl
# Optional shortcut
# make cli
# Install it somewhere on your PATH
sudo install -m 0755 ./bazel-bin/housecarl/housectl /usr/local/bin/housectl
housectl --version
This should print the installed housectl version.
Connect housectl to your Housecarl account:
housectl config login https://housecarl.cloud your-email@example.com --tenant your-org-name
You'll be prompted for your password. Enter it (it won't be displayed).
Successful login prints a status block similar to:
Logged in: yes
Username: your-email@example.com
Tenant: your-org-name
housectl also prints a separate line noting that the generated context was saved and set as current.
Note: Replace your-email@example.com with your actual email and your-org-name with the tenant name you chose during signup.
Troubleshooting: If you see authentication failed, confirm the tenant name is correct and that your user is associated with that tenant. If you’re not sure, ask your tenant admin or support to verify the association.
housectl config ping
Expected output:
Logged in: yes
Troubleshooting: If you see Logged in: no, log in again. If you need a basic server reachability check instead of a session check, run housectl config health.
Let's create a policy that allows users in the "engineering" team to read documents in the "project-alpha" folder.
We'll create a dedicated domain for the project-alpha folder so the example is fully isolated.
housectl domain create project-alpha
Now list your domains and copy the UUID for project-alpha:
housectl domain list
You'll use that UUID in the policy and request examples below.
Create a file called my-first-policy.toml:
name = "engineering-read-project-alpha"
description = "Allow engineering team to read project-alpha documents"
engine = "Glob"
deny = false
invert = false
[[statements]]
group = "engineering"
action = "read"
object = "hc://domain/<project-alpha-domain-uuid>/documents/project-alpha/*"
What this policy means:
*group attribute is "engineering"Now deploy the policy to your project-alpha domain (replace the UUID with your project-alpha domain's UUID):
housectl domain put-policies <project-alpha-domain-uuid> my-first-policy.toml
Expected output:
Successfully updated 1 policies
Now let's test if our policy works! We'll create an authorization request and check it.
Create a file called auth-request.json:
{
"context": {
"subject": {"Single": "user:alice"},
"action": {"Single": "read"},
"object": {"Single": "hc://domain/<project-alpha-domain-uuid>/documents/project-alpha/budget.xlsx"},
"group": {"Single": "engineering"}
}
}
What this request means:
Note: housectl authz can-i expects RequestValue wrappers (Single/Multiple) as shown above. The REST API accepts plain string values (no wrappers). In both cases, all attributes belong under context.
housectl authz can-i auth-request.json
Expected output:
ALLOW
Success! Alice can read the document because she's in the engineering group and the resource matches our policy.
What if Alice tries to write the document instead of reading? Create auth-request-denied.json:
{
"context": {
"subject": {"Single": "user:alice"},
"action": {"Single": "write"},
"object": {"Single": "hc://domain/<project-alpha-domain-uuid>/documents/project-alpha/budget.xlsx"},
"group": {"Single": "engineering"}
}
}
Check it:
housectl authz can-i auth-request-denied.json
Expected output:
DENY
Alice is denied because our policy only allows "read" actions, not "write".
Congratulations! You just:
Now that you've got the basics, here's where to go from here:
Q: What if I want to allow Alice to write as well?
Add "write" to the action pattern:
"action": "read|write"
Or create a separate policy for write access.
Q: How do I add more users to my tenant?
housectl user create bob Secret456! bob@example.com
housectl tenant associate-user your-org-name bob
Security note: Passing passwords as command-line arguments exposes them in shell history and process listings. In sensitive environments, disable shell history before running this command, or use a secrets manager to supply the value.
Q: Can I test policies without deploying them first?
Yes! Use housectl authz can-i-local:
housectl authz can-i-local --request auth-request.json my-first-policy.toml
This tests entirely offline without touching the server.
Q: What's this "hc://" prefix in the object?
That's the Housecarl resource URI format. It always starts with hc:// followed by the resource type and path. Think of it like http:// but for authorization resources.
Q: My authorization check says DENY but I think it should allow. How do I debug?
Check these in order:
housectl domain list-policies roothousectl tenant is-user-associated your-org-name alice/ boundariesSee Policy Administration for more debugging tips.
If you've used other authorization systems, here are the key differences:
signing_secret.housectl <command> --help for any commandReady to build something awesome? Let's go! 🚀