Manage API Keys on a Remote Machine
Store API keys on a machine and use them without pasting them into chats.
Introduction
30 Second Summary
Remote coding sessions create an awkward moment when an agent needs a secret that belongs on its machine. Pasting the value into chat leaves it behind in the transcript.
In this project, you will run llm-keys-ui on a machine you control. Its local page stores named API keys for shell commands without exposing their values in chat.
What You'll Build
Your demo ends with a shell command calling a model through a named key while the secret stays out of the chat transcript.
By the end of this project, you'll have:
- A running key manager with a local page you can open in your browser.
- At least two named keys saved from separate devices and visible on the first machine.
- A working shell command that retrieves one key by name for a real model call without placing the secret in chat.
- An optional Secret Mission to push your secure key-handling skills further.
Are there any prerequisites?
You'll need Python with uv or uvx, the llm CLI, and one API key worth protecting. Use a machine on a network you control because the page can be reachable beyond localhost. The tool is free to run, but model calls can incur provider charges.
Before We Start
Remote coding sessions can preserve every chat message. Pasting an API key there can leave a reusable secret in the transcript.
This preparation step gives the key manager a safe place to run. You will confirm that uv is available in your terminal.
You will also prepare a browser on the controlled machine. A second device will share its local network for the later access test.
In this step, get ready to:
- Prepare a controlled machine with terminal access.
- Connect a second device to the same local network.
- Keep two authorized API keys outside your chat history.
Prepare your controlled machine
The key manager stores credentials on the machine where it runs. Use a computer that you own or administer so you control access to that storage.
- Choose a computer that you own or administer.
- Press Cmd+Space on macOS or the Windows key on Windows to open system search.
- Type the name of your terminal application into system search.
- Press Enter to open the terminal application.
You should see a terminal window with a prompt where you can enter commands.
- Return to your operating system's search.
- Type the name of your installed web browser.
- Press Enter to open the browser.
You should see an empty browser window or your usual start page.
Why Use a Controlled Machine?
The key manager keeps stored values in plain text on the machine where it runs. A controlled machine lets you decide who can access those values.
Ready your network and keys
The later network test lets a second device reach a page served by your controlled machine. A local network you trust reduces the number of people who could attempt to reach that page.
- Open the network menu on your controlled machine.
- Read the name of its connected network.
- Open the network settings on your second device.
- Select the same network on the second device.
- Confirm that both devices show that network as connected.
Keep Both Keys Private
The next actions involve credentials, so keep each full value inside its current secure storage. Neither key needs to appear in chat or a terminal command.
Only use keys that you are authorized to store on the controlled machine. Keep full key values out of screenshots.
- Choose one API key that you are authorized to use.
- Keep the first key in its current secure storage.
- Choose a second API key that you are authorized to use.
- Keep the second key in its current secure storage.
- Confirm that neither full key appears in your chat history.
That sensitive preparation is complete. Both authorized keys remain outside the transcript.
Verify uv and uvx
The uvx command runs Python tools in temporary environments. It is an alias for uv tool run.
The next project step uses uvx to start the key manager. A version check confirms that the uv installation is available through your terminal.
Before you run the check, do you expect the terminal to show an installed version or say the command is unavailable?
- Check whether uv is available by running this command:
uv --version
What Does This Check Do?
The command asks the installed uv executable to identify its version. The uv installation also provides the uvx alias used in the next step.
✔️ I see a uv version
Your terminal can find uv. That confirms the uvx command is ready for the key manager.
Good work. Your command-line prerequisite is ready without exposing either API key.
ⓧ Command not found
Uv needs to be installed before the project can continue. Choose your operating system below to use the official standalone installer.
macOS
The installer downloads uv to your machine. It may update your shell configuration so new terminal windows can find the command.
- Install uv on macOS by running this command:
curl -LsSf https://astral.sh/uv/install.sh | sh
What Does This Installer Do?
The curl command downloads the official installer. The sh command runs it on your machine.
- Close the terminal window from earlier.
- Return to system search.
- Open a fresh terminal application.
- Confirm the installation by running the version check again:
uv --version
What Does the Second Check Prove?
A version in the fresh terminal confirms that your shell can find uv. The same installation provides uvx for the next step.
You should see a line that names uv and includes its installed version.
Windows
The installer downloads uv through PowerShell. The execution policy option permits the downloaded installer to run for this command.
- Install uv on Windows by running this command:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
What Does This Installer Do?
The command downloads the official uv installer through PowerShell. It runs the installer after the download finishes.
- Close the terminal window from earlier.
- Return to system search.
- Open a fresh PowerShell window.
- Confirm the installation by running the version check again:
uv --version
What Does the Second Check Prove?
A version in the fresh PowerShell window confirms that Windows can find uv. The same installation provides uvx for the next step.
You should see a line that names uv and includes its installed version.
Linux
The installer downloads uv to your machine. It may update your shell configuration so new terminal windows can find the command.
- Install uv on Linux by running this command:
curl -LsSf https://astral.sh/uv/install.sh | sh
What Does This Installer Do?
The curl command downloads the official installer. The sh command runs it on your machine.
- Close the terminal window from earlier.
- Open a fresh terminal application.
- Confirm the installation by running the version check again:
uv --version
What Does the Second Check Prove?
A version in the fresh terminal confirms that your shell can find uv. The same installation provides uvx for the next step.
You should see a line that names uv and includes its installed version.
Still Unable to Run uv?
- Close every terminal window so updated shell settings can load.
- Open a fresh terminal through your operating system's search.
- Review the official uv installation guide for another supported installation method.
- Ask for help with making uv available in my terminal.
- Leave the key-manager server stopped for this checkpoint.
- Keep both API keys in their current secure storage.
- Keep the second device connected to the same local network.
Your terminal now shows an installed uv version. Your browser is available on the same controlled machine.
Your second device is connected to the same local network. No key-manager server is running.
Your safe starting point is ready. Next, you will start the key manager and read the addresses it serves.
Start the Key Manager
Your API keys stay out of the agent transcript only if the key form runs somewhere you control. The first job is to start the form's server.
The llm-keys-ui plugin runs as a local web server. The uvx command starts it without a permanent install.
In this step, get ready to:
- Run the key-manager plugin from one uvx command.
- Distinguish the loopback URL from the local-network URL.
- Keep the server process running in an open terminal.
Keep the server on a controlled network
The --all option asks the plugin to print every address that can reach its page. This includes addresses available to other devices on your network.
Use a Network You Control
Network access makes the key form reachable beyond this machine. Keep that reach limited to a local network you trust.
- Continue only while the machine is connected to your controlled local network.
- Switch back to the terminal on your controlled machine.
- Start the key-manager server by running this command:
Before you run it, which kinds of browser addresses do you expect the server to print?
uvx --with llm-keys-ui llm keys-ui --all
What Does This Command Do?
- The uvx command prepares an isolated environment for the tool.
- The --with llm-keys-ui section adds the key-manager plugin to that environment.
- The llm keys-ui --all section starts the server with every reachable browser address listed.
You'll see startup output containing a loopback browser URL plus a local-network browser URL. Good, the key manager is now listening from the machine you control.
Server Stopped Before Showing URLs?
- Confirm that the machine can access the internet while uvx prepares the plugin.
- Retry the startup command after restoring the connection.
If the server still stops, help me diagnose the startup failure.
Identify the two browser URLs
A loopback address works only on this machine. A local area network address gives your second device a route to the same server.
Before you compare the URLs, do you expect them to use the same port?
- Find the loopback URL that follows the form http://127.0.0.1:<port> or http://localhost:<port>.
- Record the loopback URL here: your local browser URL.
- Find the local-network URL that follows the form http://<LAN-IP>:<port>.
- Record the local-network URL here: your local-network URL.
- Leave the terminal process running for the next step.
You should see a loopback URL plus a local-network URL. Both URLs should use the same port.
What Do These Addresses Prove?
The two addresses lead to the same key-manager server. The loopback address keeps access on this machine.
The local-network address supports access from your second device. That shared port confirms both routes point to one running process.
Your key manager is running with both access routes visible. Next, you'll open the local page and inspect the form it serves.
Open the Key Form
Your key-manager plugin is already running in the terminal from the previous step. Its startup output gives you two routes to the same form.
Here, you'll use the loopback address to keep this first check on the server machine. This confirms the page is available before any API key is entered.
In this step, get ready to:
- Distinguish the loopback URL from the local network URL.
- Load the loopback URL in a browser on the server machine.
- Confirm the empty key form is ready for a named key.
Identify the loopback URL
The server prints more than one address because each route has a different reach. The loopback route is the one for this machine.
- Switch back to the open terminal running the key-manager plugin.
- Locate the startup line that shows the loopback URL.
- Record the displayed URL here: your loopback URL.
Why Use the Loopback URL?
Loopback traffic stays on the machine running the server. Other devices cannot use that route.
The network address becomes relevant during the later network-access test.
Load the key form
Your browser becomes a local client for the running server. This check uses no secret values.
- Predict whether the running server will answer when the browser requests its loopback URL.
- Press Cmd+Space on macOS or the Windows key on Windows to open your search bar.
- Type the name of your web browser into the search bar.
- Press Enter to open the browser.
- Select the browser's address bar.
- Enter your loopback URL in the address bar.
- Press Enter to load the page.
You should see the key-manager page with an empty form.
One field accepts a key name. Another accepts the API-key value.
- Leave both form fields empty.
You have the local route working. Your browser can reach the key form without placing a secret in chat.
Can't See the Form?
- Confirm the key-manager process is still running in the terminal from earlier.
- Re-enter the loopback URL exactly as the terminal printed it.
- Ask for help with the connection by selecting help me diagnose why the key form does not load.
The form is open without any stored keys. Next, you'll use it to save your first named key.
Save Your First Key
Your local llm-keys-ui form is already running in the browser. The form gives your key a route into the machine that bypasses chat or terminal history.
An API key is a live credential that lets software use a service under your account. You will save your first authorized key as MODEL_API_KEY through the local form.
In this step, get ready to:
- Give your first authorized key the name MODEL_API_KEY.
- Save the value through the local browser form.
- Confirm the stored-key list shows MODEL_API_KEY.
Set the key name
A stable name lets other tools refer to a credential without exposing its value. You will use MODEL_API_KEY as that handle.
- Return to the key-manager form in the browser from earlier.
- Enter MODEL_API_KEY in the field for the key name.
You should see MODEL_API_KEY in the key-name field. The secret value has not entered the form yet.
Why Name the Key?
The key name becomes a stable handle for the credential. A tool can request MODEL_API_KEY without placing the secret in your conversation.
Save the first key
This is the sensitive moment. Your key stays out of the agent transcript when you enter it only in the local browser form.
Keep the Credential Local
Text entered in chat can remain in a transcript. Text entered in a terminal can remain in shell history.
The local browser form sends the credential to the key manager on the machine you control. The interface does not let you read existing key values later.
Before you save, do you expect the stored-key list to show the key name, the secret value, or both?
- Paste your first authorized API key directly into the form field for the API-key value.
- Select the form's save control.
You'll see the stored-key list with MODEL_API_KEY. The secret value remains unavailable through the interface.
That careful handoff is complete: the key manager now holds your credential under MODEL_API_KEY.
Key Name Missing From the List?
- Check that the key-manager server is still running in the terminal from earlier.
- Return to the local form from earlier if the browser reports a connection problem.
If the name still does not appear, help me diagnose why MODEL_API_KEY is missing from the stored-key list.
Your first key is stored without entering chat or terminal history. Next, you will prove that a command can use the credential by name.
Use the Key by Name
Your first API key now lives behind the local form under MODEL_API_KEY. The next goal is to use that stored credential from the shell.
The llm CLI can resolve a stored key name when it sends a model request. Can the request succeed without pasting the secret into the command or chat?
In this step, get ready to:
- Retrieve the stored credential by requesting MODEL_API_KEY from the shell.
- Send a real model prompt using the stored key name.
Keep the secret out of your transcript
A named lookup separates the reference from the secret. The shell uses MODEL_API_KEY to find the stored value.
- Leave the key-manager server running in the terminal from earlier.
- Press Cmd+Space on macOS or the Windows key on Windows to open system search.
- Type terminal into system search.
- Select the terminal application shown in the results.
Keep This Output Private
The next command prints the secret into your terminal. This is a private check on a machine you control.
- Keep the terminal out of screenshots while the value is visible.
- Leave the value in the terminal without copying it into chat.
Before you run this, predict whether the shell returns the key name or the stored value.
- Request the stored value by name by running this command:
uvx --with llm-keys-ui llm keys get MODEL_API_KEY
What Does This Command Prove?
- The uvx command runs LLM in its managed environment.
- The --with llm-keys-ui option includes the key-manager plugin.
- The llm keys get command looks up the credential stored under MODEL_API_KEY.
You will see the stored credential value printed as one line. You have the named lookup working.
Key Lookup Failed?
- Confirm that the command spells MODEL_API_KEY exactly as it appears in the stored-key list.
- Return to the browser from earlier to confirm that MODEL_API_KEY still appears in the list.
If the lookup still fails, help me debug the named-key lookup.
Send a real model request
A model call can accept the stored alias through --key. LLM resolves MODEL_API_KEY before it authenticates the request.
This Makes a Real API Call
Your provider counts this short prompt as API usage. A single response is enough to prove the credential handoff.
Before you run this, predict whether the model can respond with only the stored key name in the command.
- Send a prompt through your configured default model by running this command:
uvx --with llm-keys-ui llm "Five friendly names for a pet skunk" --key MODEL_API_KEY
How Does the Handoff Work?
- The prompt asks your configured default model to generate five names.
- The --key option tells LLM which stored credential alias to resolve.
- The command contains MODEL_API_KEY without containing the secret value.
You will see five suggested names stream into the terminal. That is the handoff working.
Your command used the stored alias to authenticate a live model request. The secret stayed out of the command itself.
Model Request Failed?
- Confirm that the stored credential belongs to the provider used by your configured default model.
- Check that the machine can reach the internet.
- Review your provider account to confirm that the key remains authorized for model requests.
If the request still fails, help me debug the named-key model request.
- Scroll the terminal until the raw key from the earlier lookup is outside the visible area.
- Capture only the model command and its generated response.
Your shell can now use a credential by name without placing its value in the command or chat. Next, you will save another key from a second device on your local network.
Add a Key From Another Device
Your first named key already works from the shell. That success proves the local workflow can protect an API key from chat history.
The final test reaches the form from a second device through your local network. A second named key will prove that both devices share one key store.
In this step, get ready to:
- Reach the key form from a second device using the displayed LAN URL.
- Save an authorized key under the name SECOND_MODEL_API_KEY.
- Confirm both stored key names from the first machine.
Open the key form on your second device
A loopback URL points a browser back to the device it is already using. The LAN URL points another device at the running key manager.
Keep the Network Boundary Small
The LAN page is available to devices that can reach your machine. A private network you control limits who can attempt to connect.
- Locate the LAN URL in the startup output by switching back to the open server terminal.
- Record the displayed address here: your LAN URL.
You now have the exact network address printed by the running server.
Before you load the LAN address, predict whether the second device will show the same key form.
- Open the available web browser on your second device.
- Load the key form by entering your LAN URL in the browser address bar.
You should see the same key form that is open on the first machine. This confirms that the second device can reach the running key manager.
Can't Reach the Form?
- Confirm both devices are connected to the same local network.
- Check that the open terminal still shows the key-manager server running.
- Re-enter the recorded LAN URL exactly as it appears in the startup output.
If the page still will not load, help me diagnose access to the key form from my second device.
Save the second named key
A key name gives the shell a safe reference for the credential. The secret value remains inside the key manager on the first machine.
Protect the Second Credential
The next form entry handles a live credential. The browser form keeps its value out of chat history. The key manager stores the value in plain text on the first machine.
- Enter SECOND_MODEL_API_KEY in the form's field for the key name.
- Paste your second authorized API key directly into the form's secret-value field.
- Submit the key using the form's save control.
The stored-key list on the second device should now include SECOND_MODEL_API_KEY.
Don't See the Second Key Name?
- Check that the saved name matches SECOND_MODEL_API_KEY exactly.
- Confirm that the server terminal remains open on the first machine.
- Reload the form on the second device to update its stored-key list.
For help without sharing the credential, help me debug why my second named key is missing.
Confirm both keys on the first machine
Both browser views read from the key manager running on the first machine. Refreshing the original view tests whether the second device wrote to that shared store.
Before you refresh the first machine, predict whether its list will contain one key name or two.
- Switch back to the key-manager browser page on the first machine.
- Refresh the stored-key list in that browser.
You should see MODEL_API_KEY in the list. You should also see SECOND_MODEL_API_KEY.
Only See One Key Name?
- Refresh the first machine's browser page once more.
- Compare the second stored name with SECOND_MODEL_API_KEY.
- Confirm that both browser pages use addresses printed by the same running server.
If the lists still disagree, help me trace the two browser connections safely.
That is the cross-device proof complete: a second device added a credential that the first machine can identify by name.
Secret mission
Audit the Key Manager's Network Boundary
Audit the key manager's access boundary by trying its loopback URL from a second device. Prove that the LAN URL works across your trusted network while the loopback URL stays tied to one machine.
Clean Up Your Resources
Clean Up Your Resources
The key manager itself has no ongoing charge, but your API provider may still bill future model calls. Choose the cleanup option below based on whether you need these stored keys again.
Resources you used:
- Key-manager plugin process running in the open terminal.
- Stored key entry named MODEL_API_KEY.
- Stored key entry named SECOND_MODEL_API_KEY.
Stopping Is Not Deleting
Stopping the server closes access to the browser form. The stored keys remain on the machine until you remove their entries.
Keep everything running
No action needed. Choose this only while the machine stays on a network you control.
- Keep the key-manager process running in the open terminal.
- Use the loopback browser page when working on the first machine.
- Use the displayed LAN address only from devices on a network you control.
- Request MODEL_API_KEY or SECOND_MODEL_API_KEY by name when a future shell command needs that credential.
The stored values remain in plain text on this machine. Future model requests may create charges with your API provider.
Pause - I'll come back to this later
Shut down the running process to close the web interface. Your named keys remain on the machine for later use.
- Return to the open terminal where the key manager is running.
- Press Ctrl+C to stop the server.
- Refresh the local key-manager page on the first machine.
Your browser should no longer reach the form. This confirms the LAN page is also unavailable through that stopped server.
- Close the key-manager browser tab on the first machine.
- Close the key-manager browser tab on the second device.
Delete - I don't want to use this again
Remove all project resources from this machine. The key manager cannot restore a stored entry after you remove it.
- Return to the key-manager form already open on the first machine.
- Use the removal control beside MODEL_API_KEY to delete its stored entry.
- Use the removal control beside SECOND_MODEL_API_KEY to delete its stored entry.
- Confirm the stored-key list no longer shows either name.
- Return to the open terminal where the key manager is running.
- Press Ctrl+C to stop the server.
- Refresh the local key-manager page on the first machine.
Your browser should no longer reach the form. The server is stopped after both local key copies have been removed.
- Close the key-manager browser tab on the second device.
Nice Work!
Nice Work!
Brilliant work! Your machine now stores two named API keys without exposing their secret values in chat or terminal history. A real model request can retrieve one of those keys by name.
You've learned how to:
- Start a local key manager with uvx. Read its loopback address from the startup output. Identify its LAN address for access from another device.
- Save MODEL_API_KEY through the local browser form. Use that named key in a real model request without pasting its secret value into chat or terminal history.
- Open the LAN address from a second device. Save SECOND_MODEL_API_KEY there. Confirm both named keys from the first machine.
- Complete the optional Secret Mission to push this safer credential workflow further.
Ready to quiz yourself?