[GUIDE] Custom Aragon Organization Deployment using the CLI

EDIT: This guide has been migrated to https://hack.aragon.org/docs/guides-custom-deploy and there may be updates there that are not reflected here!

The following steps are intended to document the process I used to deploy a blank organization and configure it to meet the needs of the Aragon Cooperative. I plan to write a more extensive guide on deploying custom organizations using the CLI soon, but figured this may be helpful information for others in the mean time. Give it a shot, and let me know if something doesn’t work or just doesn’t make sense.

Major shoutout to @danielconstantin @gabi @bingen @Quazia for work on the CLI to make this possible, and for supporting me as I learned all the new features!

In order to get started you will need the latest version of the CLI installed so open a terminal and enter the following:

npm install -g @aragon/cli

Note: the features used in this are brand new, and some may still be a bit buggy, i’ll make some notes where I think there may be an unresolved issue

In order to deploy to rinkeby or mainnet using the CLI you will either need to use a hardware wallet with Frame or configure CLI sign transactions using a private key (would love to link to documentation on this but don’t see it anywhere on hack.aragon.org).

If you decide to use frame, just add --use-frame to any of these commands.

If you are testing locally:

  • in a separate terminal run aragon devchain
  • in a separate terminal run aragon ipfs

if you are deploying to rinkeby:

  • add --environment aragon:rinkeby to each of these commands

if you are deploying to mainnet:

  • add --environment aragon:mainnet to each of these commands

Creating a blank organization

dao new

This will create a new organization based on default “bare-kit” it won’t have a token manager, vault, finance, or voting instance installed. Make a note of the deployed DAO address as we will need it for subsequent commands.

Note: there appears to be an issue with this command on rinkeby/mainnet that causes it to fail with a gasLimit error sometimes. github issue

Adding a Token and Token Manager instance

Aragon uses tokens to represent groups, token balances can be capped to a certain amount per account made non-transferrable. The following are 3 common scenarios:

Membership: A non-transferrable token limited to 1 per account
Reputation: A non-transferrable token without balance restriction
Equity: A transferrable token without balance restriction

For the cooperative we want to start with a membership token.

First we need to deploy a minime token, using the dao new token command. The syntax is as follows:
dao token new <token-name> <symbol> [decimal-units] [transfer-enabled]

For a membership token we want to set decimal units to 0 (default is 18), we can leave [tranfer-enabled] as default, as we will restrict transferability using the token-manager in a subsequent step. So we end up with:

dao token new "Member" "MBR" 0

Make a note of the token address as we will need it later!

Next we need to deploy an instance of the token-manager app which will serve as the token-controller for the minime token we just deployed. The token-manager cannot be initialized unless it is already the controller of a minime token, so we want to use dao install command with the --app-init none argument, that way we can perform some actions before we initialize it.

dao install [dao-address] token-manager --app-init none

In order to get the token-manager address we need to run the following command:

dao apps [dao-address] --all

You should see a list of apps, and a token-manager instance listed under permissionless apps, make a note of this address as we will need it later.

Next we want to set the token-manager instances as the token-controller on our token.

dao token change-controller <token-address> <token-manager-address>

Next we want create a permission for the token-manager.

dao acl create [dao-address] [token-manager-address] MINT_ROLE [your-address] [your-address]

Now we can actually initialize the token manager using the dao exec command. The token-manager’s initialize function takes 3 parameters, the address of a minimetoken, a boolean indicating if the token should be transferrable, and an uint determining max number of tokens an address can control (use 0 if you do not want to restrict balances).

For a membership token we would initialize like this:

dao exec [dao-address] [token-manager-address] initialize [token-address] false 1

At this point if you open your DAO in a web browser you should see the token manager app installed, and should be able to mint tokens from [your-address]

Even though we have initialized the token manager as transferrable = false, and token transfers fail, there is what appears to be a UI bug where the token manager will list the token as transferrable even though it is not. Github Issue

Adding a Voting instance

Adding a voting app allows actions to be protected by a vote, each instance is associated with a token, but you can have multiple voting instances per token, with each instance having different parameters. A common case might be to have some actions require a simple majority, while other require a super-majority. We will create on voting app instance, but the process can be repeated as many times as required.

Since we already have a token and token manager deployed all way have to do is install the app, this can be done in one step using the dao install command and passing arguments via --app-init-args

The voting app requires the following initialization parameters:

  • minime token: address of a minime token
  • support required percentage: Percentage of yeas in casted votes for a vote to succeed (expressed as a percentage of 10^18; eg. 10^16 = 1%, 10^18 = 100%)
  • min accept quorum: Percentage of yeas in total possible votes for a vote to succeed (expressed as a percentage of 10^18; eg. 10^16 = 1%, 10^18 = 100%)
  • vote time: Seconds that a vote will be open for token holders to vote (unless enough yeas or nays have been cast to make an early decision)

So if we want a voting app instances with a support requirement of 60% and min accept quorum of 25% and a voting period of 7 days we would use the following command.

dao install [dao-address] voting --app-init-args [token-address] 600000000000000000 250000000000000000 604800

Next you will need to assign the create votes permission, if you want all token holders to be able to create votes, we can assign the CREATE_VOTES_ROLE to the [token-manager-address], you can also set permissions to the voting app itself. The following command grants token holders the ability to create votes, and requires a vote to manage changes to the permission.

dao acl create [dao-address] [voting-app-address] CREATE_VOTES_ROLE [token-manager-address] [voting-app-address]

At this point you should be able to open your organization and create votes :clap:

Adding a Vault and Finance instance

The vault is intended to securely store and manage funds but does not have its own user interface. The Finance app provides an interface and provides some limited budgeting capabilities. In the future, it may make sense to install the vault app without the finance app, or the finance app with a different version of the vault app, but for now these two apps generally make sense to install as a pair.

The vault can be installed and does not require passing any specific initialization parameters
dao install [dao-address] vault

The finance app requires to initialization parameters: a vault instance address and budgeting period (in seconds). If you are familiar with the finance app in the UI, you may have noticed that there is not way to configure or set a budget, however, the contracts allow you to set a per-asset budget which is reset each time period. Eventually the UI will be updated to support these functions. If you don’t intend to use any of the budgetting functionallity the budget period parameter doesnt matter but it does need to be passed. If you do plan on using the budgeting functionality here is the how it works:

For a given budget period P, a budget B can be set for asset A. The total volume of transfers of A cannot exceed its budget within a period P. So for example, if we initialize P as 1 Month, we could set a budget for DAI of 1000, and even if the vault contains more than 1000 DAI it will not be able to spend more than 1000 DAI per month. Keep in mind that the budget is not exposed in the UI, so transactions which exceed the budget will just fail.

Lets set install a finance instances with a budget period of 30 days:

dao install [dao-address] finance --app-init-args [vault-address] 2592000

Now we want to create a permission that grants the finance app the transfer role on the vault, we will make have voting be required to manage the permission.

dao acl create [dao-address] [vault-address] TRANSFER_ROLE [finance-address] [voting-address]

We also want to grant some permissions on the finance app to the voting app:

dao acl create [dao-address] [finance-address] CREATE_PAYMENTS_ROLE [voting-address] [voting-address]

dao acl create [dao-address] [finance-address] EXECUTE_PAYMENTS_ROLE [voting-address] [voting-address]

dao acl create [dao-address] [finance-address] MANAGE_PAYMENTS_ROLE [voting-address] [voting-address]

For more information on what each of these roles do as well as additional roles made available by the finance app, see the wiki

At this point you should be able to open your dao, manage tokens, create votes, and manage funds using vault and finance apps.

Review & Finalize Permissions

While we have a mostly functional DAO the permissions need to be cleaned up because we do not want our personal address to have root authority in the organization. These steps can be done using the CLI as described bellow, or if you prefer you can do it using the permissions UI.

We can see what permissions are currently assigned using the dao acl command

dao acl [dao-address]

You will notice that some key permissions have been granted and are managed by the address you used to perform these commands. By following these steps you are transferring authority as the creator of the organization to other applications and entities defined above, it is an inreversible process, so be careful not to revoke a permission before granting it to an appropriate entity.

  1. You’ll want to grant permissions which are currently only assigned to your address to another entity (eg [voting-address]).

dao acl grant [dao-address] [app-address] [ROLE] [entity-address]

  1. You’ll want to revoke permissions for yourself once they have been granted to another entity

dao acl revoke [dao-address] [app-address] [ROLE] [your-address]

  1. You’ll want change the permission manager for permissions from your address to another entity (eg [voting-address])

dao acl set-manager [dao-address] [app-address] [ROLE] [entity-address]


Great guide, thanks for putting this together. Looking forward to going through it fully.

I have a question - why didn’t you create the minime token with transfers disabled in that first strep?

From what I can observe from the code, my guess is that the script.js is actually not handling updating this state change that you do in the second step when you’re adding the token manager. I didn’t see anything related to updating the transfersEnabled bool in the script.js

I think if you disabled transfers in the first step when creating the minime it should at least display properly in the UI if you also passed false in the second step as well (false / false )

I think the way you did it is simply changing the minime parameter in the second step, so you’re setting it after the fact. If you did false then true, it would simply do the reverse (it enable transfers, but the UI will display it incorrectly as non-transferable since that was the first state and the script.js is missing this state change). I think.

Someone tell me if I’m right :slight_smile:


I’m fairly sure I tried that permutation when testing without success, but I agree that it would make sense. If thats the case though there is still a display bug that needs to be resolved.

Edit: I confirmed that setting both the token and the token manager to transfer == false still has the display issue on the token manager.

1 Like

I think it might be interesting to add to this section a more generic guide on how to

  1. publish an app to open.aragonpm.eth
  2. list applications already on open.aragonpm.eth
  3. install applications from open.aragonpm.eth

Would love to be able to test out some of apps that were shown off at Aracon–futarchy, the planning suite, pando, espresso. (on rinkeby of course :innocent:)


I’ve just completed this guide using a local deployment (as opposed to using rinkeby/mainnet) and experienced a couple of issues which might be useful for others to hear.

Firstly, to see the UI on a local deployment, I downloaded this repo: aragon/aragon and in the root directory, executed npm run start:local after doing run aragon devchain and run aragon ipfs in separate terminals. Then to see my DAO’s UI, I went to http://localhost:3000/#/[DAOAddress]. The DAO address is found after executing dao new.

Secondly, I had an issue executing the last command in the section “Adding a Token and Token Manager instance”, specifically the command dao exec [dao-address] [token-manager-address] initialize [token-address] false 1. This returned a contract revert error. I think this was due to the exec function setting an insufficient gas limit. When I executed the same transaction using Remix with a high gas limit, (set in MetaMask, not Remix btw) it worked for me.

Side note, to execute the initialize function in Remix:
I copied the initialize function signature into an empty contract ->
Loaded the address of the TokenManager, as shown in dao apps [dao address] --all, with the “At Address” field ->
Executed the initialize function now available in the contract which shows in the “deployed contracts” section.


for interacting with the cli on rinkeby you can configure a private key in ~/.aragon/

$ cat ~/.aragon/rinkeby_key.json
  "rpc": "https://rinkeby.infura.io",
  "keys": [

then if you use --environment aragon:rinkeby when using the cli commands it will use that account

Thanks for this Luke!

I got this I tried to the initialized token manager:

âś– Sending transaction
   → Returned error: VM Exception while processing transaction: revert TM_TOKEN_CONTROLLER

Any idea what I might’ve done wrong?

1 Like

find your DAO UI here:
https://rinkeby.aragon.org/#/[DAO Address]


I have the same problem. The issue is already in github.

Apparently, it works in rinkeby…

1 Like

Thank you for this @lkngtn it really is excellent, and works like a charm on Rinkeby! Bravo!

One thing which was slightly confusing - some commands seemed to execute successfully, BUT threw an error:

âś– Cannot read property 'description' of undefined

Specifically, it was the dao acl commands to assign MINT_ROLE, CREATE_VOTES_ROLE, CREATE_PAYMENTS_ROLE roles.

This, plus a few minor pieces of feedback are in this issue.

1 Like

Thanks @chrishobcroft – I don’t think there has been major changes since this post but the guide has been migrated to https://hack.aragon.org/docs/guides-custom-deploy (I will edit the op to reflect that :slight_smile: ).

cc: @gabi I’ve also experienced the cannot read property issue, though I may never have reported it. Is this a known issue tracked in the CLI repo somewhere?

@lkngtn, @chrishobcroft I just review the issue and is related on how the aragonCLI handle the transaction path description. Now the wrapper handle tx descriptions diferently, so we need to update as well. I have created an issue to track that change. Thank you both for report it :slightly_smiling_face:

It’s not just a display issue. You can always transfer the tokens if you set the gas limit high enough. See https://github.com/aragon/aragon-apps/issues/630 . I have confirmed that tokens are transferable even after setting transferable to false for the token new and dao exec command (to initialize the token manager.)

Thanks @adamstallard! Lets re-open that issue, and discuss there.

Also just want to confirm what you are doing:

  1. setting transferrable to false when generating the token eg dao token new "Member" "MBR" 0 false
  2. when initializing the token manager you are also indicating transferability should be false dao exec [dao-address] [token-manager-address] initialize [token-address] false 1

Yes. I’ve done that 4 times with the same result each time. Have you been able to create a non-transferable token through the CLI? Also that github issue makes it seem like it’s a display issue. If we want to discuss this in that issue, it should be renamed so it’s more clear what the issue is.

1 Like

I explained what happened in the issue thread. Thanks for reporting it Adam.

1 Like