informalsystems / themis-contract Goto Github PK
View Code? Open in Web Editor NEWA command line-based parameterized contracting tool
License: Apache License 2.0
A command line-based parameterized contracting tool
License: Apache License 2.0
A nice workflow might be something along the lines of the following:
neat-contract review <giturl>
neat-contract execute <contract-name>
Where review
would take care of
and execute
would take care of
The longish command names have short aliases, but these don't seem to be visible to the user from the help menu.
It should be possible to specify a template URL on new
to fetch the template from the web. This will facilitate using a common set of templates stored in a canonical location, rather than having to copy them around.
We should also probably create an index of templates in a local profile so we can refer to them by name, ie. --template-id employee
could look up employee
in a local config file to find the URL where to pull from.
Wasn't clear if/how this relates to #6
Following from #49, once we have settled the contract format/templating approach for the next iteration of the prototype, let's try to figure out a good approach to dealing with the conversion to/from Microsoft Word format, while preserving all the relevant contract source elements in that conversion.
We should have some kind of sub-command to help automatically update the hash of a template in a contract to the latest hash. It's a pain to have to manually run sha256sum contract-template.md
and copy/paste the hash every time one updates a template.
[sf@comp informal-shares-certificate]$ pwd
/home/sf/Sync/informal-systems/contracts/contract-templates/informal-shares-certificate
[sf@comp informal-shares-certificate]$ themis-contract new --template ./informal-shares-certificate-template.md ./example/contract.toml
2020-05-13 18:01:23 error ENOENT: no such file or directory, open '/home/sf/Sync/informal-systems/contracts/contract-templates/informal-shares-certificate/example/informal-shares-certificate-template.md'
Note: I'm telling it the template is located relative to the current directory via --template ./informal-shares-certificate-template.md
, but it's failing to find a file located relative to a directory in the path of the destination for the contract.
I'm getting
$ go get github.com/informalsystems/themis-contract
go get github.com/informalsystems/themis-contract: invalid github.com/ import path "github.com/informalsystems"
No idea why, despite too long trying to understand how go handles packaging.
Pandoc is very flexible and extensible. If we provide a way for users to specify a pandoc default file to use, we can expose this flexibility as an escape hatch.
When porting a contract I often need to make a change, then recompile to view the results, then make a change. It saves a lot time to have the recompilation performed automatically on safe. I hack this functionality for my purposes with bash function, but it would helpful and convenient to have this functionality built in to the tool.
My bash function runs:
themis-compile-watch () {
local template="$1"
local contract="$2"
if [ -z "$template" ] || [ -z "$contract" ]; then
echo "Must supply a template file and the contract configuration"
return
fi
while inotifywait -e close_write "$template" "$contract"; do
themis-contract compile "$contract"
done
}
Related to #35 - do we really need to copy in those fonts (Roboto and Sacramento)? Can we not make fonts some optional extra installation step that folks can worry about later in the documentation when they want to customize their contracts?
We've seen in numerous cases that mandatory and by-default Integration with keybase introduces lots of failure points and complexity. Here are the cases that come to mind:
For our current needs, it seems like making this integration an opt-in addition would be more expedient.
This was discussed in our walk through last week.
It might end up being a legal requirement in Canada that, for users' signatures to be considered binding, they be allowed to customize the font they use for signing documents.
Right now we have a really cumbersome way of selecting fonts for signing contracts that is macOS- and Linux-specific:
> fc-list | grep -i cursive
/Users/thane/Library/Fonts/CedarvilleCursive-Regular.ttf: Cedarville Cursive:style=Regular
> neat-contract sign --font "Cedarville Cursive"
It would be ideal if the sign
command offered the option to allow the user to select from a predefined set of fonts. We could potentially download and package a range of fonts with neat-contract
and offer these fonts for signing.
We should look into adding Dhall support for contract parameters files to enable computation and type checking into the tooling.
2020-05-13 19:07:56 debug Attempting to load template as file: /home/sf/Sync/informal-systems/contracts/contract-templates/informal-shares-certificate/informal-shares-certificate-template.md
2020-05-13 19:07:56 debug Found potential template variable: share
2020-05-13 19:07:56 debug Found potential template variable: ordinal
2020-05-13 19:07:56 debug Found potential template variable: shareholder
2020-05-13 19:07:56 debug Found potential template variable: name
2020-05-13 19:07:56 debug Found potential template variable: certificate_date
2020-05-13 19:07:56 debug Found potential template variable: counterparties_list
2020-05-13 19:07:56 debug Found potential template variable: full_name
2020-05-13 19:07:56 debug Found potential template variable: signatories_list
2020-05-13 19:07:56 debug Found potential template variable: signature_image
2020-05-13 19:07:56 debug Found potential template variable: signature_image
2020-05-13 19:07:56 error string "" is not a function
TypeError: string "" is not a function
at eval (eval at createFunctionContext (/home/sf/Sync/informal-systems/contracts/neat-contract/node_modules/handlebars/lib/handlebars/compiler/javascript-compiler.js:260:23), <anonymous>:11:5)
at prog (/home/sf/Sync/informal-systems/contracts/neat-contract/node_modules/handlebars/lib/handlebars/runtime.js:333:12)
at Proxy.<anonymous> (/home/sf/Sync/informal-systems/contracts/neat-contract/node_modules/handlebars/lib/handlebars/helpers/block-helper-missing.js:32:14)
at Proxy.wrapper (/home/sf/Sync/informal-systems/contracts/neat-contract/node_modules/handlebars/lib/handlebars/internal/wrapHelper.js:10:19)
at eval (eval at createFunctionContext (/home/sf/Sync/informal-systems/contracts/neat-contract/node_modules/handlebars/lib/handlebars/compiler/javascript-compiler.js:260:23), <anonymous>:11:69)
at prog (/home/sf/Sync/informal-systems/contracts/neat-contract/node_modules/handlebars/lib/handlebars/runtime.js:333:12)
at Proxy.<anonymous> (/home/sf/Sync/informal-systems/contracts/neat-contract/node_modules/handlebars/lib/handlebars/helpers/block-helper-missing.js:32:14)
at Proxy.wrapper (/home/sf/Sync/informal-systems/contracts/neat-contract/node_modules/handlebars/lib/handlebars/internal/wrapHelper.js:10:19)
at eval (eval at createFunctionContext (/home/sf/Sync/informal-systems/contracts/neat-contract/node_modules/handlebars/lib/handlebars/compiler/javascript-compiler.js:260:23), <anonymous>:13:98)
at prog (/home/sf/Sync/informal-systems/contracts/neat-contract/node_modules/handlebars/lib/handlebars/runtime.js:333:12)
The section of the template it's dying on:
+--------------------+-----------------------------------------------------+
| Parties | Signatories |
+:===================+:====================================================+
{{#counterparties_list}}
| | |
+--------------------+-----------------------------------------------------+
| {{full_name}} |
{{#signatories_list}}
+--------------------+-----------------------------------------------------+
| | |
+--------------------+-----------------------------------------------------+
{{#signature_image}}
| | |
| | ![]({{&signature_image}}) |
| | |
{{/signature_image}}
| | |
| | {{full_names}} |
| | |
{{#title}}
| | |
| | Title: {{.}} |
| | |
{{/title}}
| | |
| | Date: {{signed_date}} |
| | |
{{/signatories_list}}
+--------------------+-----------------------------------------------------+
{{/counterparties_list}}
Thank you unsound, gradual type checking!
This is something that users will always need to work with contracts effectively, and since we already require running the init
command after installation, we should set this up as well.
This is just due to a hard-coded local path:
[sf@comp themis-contract]$ themis-contract new git://github.com:informalsystems/themis-contract/examples/service-agreement/contract.dhall#prototype/v2 -v
6:24PM DBG Increasing output verbosity to debug level
6:24PM DBG Themis Contract home directory present: /home/sf/.themis/contract
6:24PM DBG Initializing profiles in /home/sf/.themis/contract
6:24PM DBG Successfully loaded profile database configuration: &{ <nil> map[] }
6:24PM INF Loading contract: git://github.com:informalsystems/themis-contract/examples/service-agreement/contract.dhall#prototype/v2
6:24PM DBG Attempting to resolve Git file reference: git://github.com:informalsystems/themis-contract/examples/service-agreement/contract.dhall#prototype/v2
6:24PM DBG Looking up cached entries for Git URL: git://github.com:informalsystems/themis-contract/examples/service-agreement/contract.dhall#prototype/v2
6:24PM DBG Git repository git://github.com:informalsystems/themis-contract is already cached at /home/sf/.themis/contract/cache/git/github.com/informalsystems/themis-contract
6:24PM INF Fetching ref "prototype/v2" from git://github.com:informalsystems/themis-contract to /home/sf/.themis/contract/cache/git/github.com/informalsystems/themis-contract
6:24PM DBG git fetch origin output:
From github.com:informalsystems/themis-contract
* branch prototype/v2 -> FETCH_HEAD
6:24PM DBG git checkout output:
Already on 'prototype/v2'
Your branch is up to date with 'origin/prototype/v2'.
6:24PM DBG Computed hash of /home/sf/.themis/contract/cache/git/github.com/informalsystems/themis-contract/examples/service-agreement/contract.dhall as a0521348223372feaaf24546c222e0526b2f50429722ae03fdd726d810cce1d0
6:24PM DBG Resolved location "git://github.com:informalsystems/themis-contract/examples/service-agreement/contract.dhall#prototype/v2" as file in a Git repository: FileRef{Location: "git://github.com:informalsystems/themis-contract/examples/service-agreement/contract.dhall#prototype/v2", Hash: "a0521348223372feaaf24546c222e0526b2f50429722ae03fdd726d810cce1d0", localPath: "/home/sf/.themis/contract/cache/git/github.com/informalsystems/themis-contract/examples/service-agreement/contract.dhall"}
6:24PM DBG Converting Dhall file to JSON: /home/sf/.themis/contract/cache/git/github.com/informalsystems/themis-contract/examples/service-agreement/contract.dhall
6:24PM DBG dhall-to-json output:
{
"params": {
"hash": "aa7a53a2bf16c44b0df8839e1bbc2529b30194e6467dd5300da4dcb56f01a9f0",
"location": "/Users/thane/Work/informal/github/themis-contract/examples/service-agreement/params.dhall"
},
"template": {
"file": {
"hash": "075ffbc7233ef0fa117d77953016ec53bfa4b34c63c802a1ce12e442a0beaf15",
"location": "/Users/thane/Work/informal/github/themis-contract/examples/service-agreement/contract.md"
},
"format": "Mustache"
}
}
6:24PM DBG Resolved location "/Users/thane/Work/informal/github/themis-contract/examples/service-agreement/params.dhall" as a local file
6:24PM ERR Failed to create new contract error="open /Users/thane/Work/informal/github/themis-contract/examples/service-agreement/params.dhall: no such file or directory"
Seems like the fix for this should be easy, but the most obvious fix (just have the location point to the remote file) won't work, because it creates a circular dependency on the hash.
As per the conversation on #48, we're probably going to need a package management system for Themis Contract templates. Before we can design it though, we're going to need to decide on:
Perhaps (1) and (2) above will be the same. My feeling is we're going to head in a similar direction (conceptually, not in structure) to how DOCX and ODT files are structured: as a package that contains files that are organized into standardized folders.
Currently, when a user goes to sign a document they are prompted to pick the from all the signatories pertaining to a document. However, in general a user should only every sign a document as a signatory for whom they have an ID configured via save-identity
. We should filter the signatories to pick from through the saved identities.
Assuming it is not possible to reduce the amount of filed downloaded instead.
This is motivated by two intersecting dynamics:
Towards implementation: The prepare
subcommand proposed in #46 could be used to prepare a directory that includes
At present, our data model is as follows:
In this model we have contracts, which have two or more counterparties. Counterparties are currently always treated as collectives with one or more signatories. An identity is effectively a special case of a signatory, and allows a user to sign a contract as that particular signatory.
There are two issues with this approach:
From these two suggestions, our model can be altered to resemble the following:
In this new model, a contract has two or more counterparties (as in the old model). Here, however, a "counterparty" is an abstract base entity (doesn't actually exist), but is realized through either a signatory (a single signer) or a collective counterparty (e.g. a company with one or more signatories).
A profile is used to store information locally on a user's machine about that user. Users can have multiple profiles because sometimes they may have to sign on behalf of different entities.
Suggested by @andynog during usage
As an enhacement the neat-contract tool could have an option something like neat-contract compile --update-template that would force it to update to the latest on master
Just hitting this as I try to compile a contract. I'll report back as I figure anything else about it:
$ themis-contract compile contract.dhall
10:37PM INF Loading contract: contract.dhall
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x7d6226]
goroutine 1 [running]:
github.com/informalsystems/themis-contract/pkg/themis-contract.(*Profile).getProfileContractByID(0x0, 0x7ffd836c433a, 0xe, 0xc00018fb00)
$HOME/Sync/informal-systems/contracts/themis-contract/pkg/themis-contract/profile.go:341 +0x26
github.com/informalsystems/themis-contract/pkg/themis-contract.fileRefType(0x7ffd836c433a, 0xe, 0xc000100410, 0xc0000769c0, 0x0)
$HOME/Sync/informal-systems/contracts/themis-contract/pkg/themis-contract/file_ref.go:363 +0x90
github.com/informalsystems/themis-contract/pkg/themis-contract.ResolveFileRef(0x7ffd836c433a, 0xe, 0x0, 0x0, 0xc000076900, 0xc000100410, 0x20, 0x1, 0x1)
$HOME/Sync/informal-systems/contracts/themis-contract/pkg/themis-contract/file_ref.go:58 +0x5a
github.com/informalsystems/themis-contract/pkg/themis-contract.loadContractComponents(0x7ffd836c433a, 0xe, 0x1, 0xc000100410, 0x1, 0x1, 0x6)
$HOME/Sync/informal-systems/contracts/themis-contract/pkg/themis-contract/contract.go:140 +0x53
github.com/informalsystems/themis-contract/pkg/themis-contract.Load(0x7ffd836c433a, 0xe, 0xc000100410, 0x0, 0x0, 0x0)
$HOME/Sync/informal-systems/contracts/themis-contract/pkg/themis-contract/contract.go:113 +0xfa
main.compileCmd.func1(0xc00013cdc0, 0xc000065100, 0x1, 0x1)
$HOME/Sync/informal-systems/contracts/themis-contract/cmd/themis-contract/compile.go:24 +0x55
github.com/spf13/cobra.(*Command).execute(0xc00013cdc0, 0xc0000650d0, 0x1, 0x1, 0xc00013cdc0, 0xc0000650d0)
$HOME/go/pkg/mod/github.com/spf13/[email protected]/command.go:846 +0x2c2
github.com/spf13/cobra.(*Command).ExecuteC(0xc00013c840, 0x0, 0x0, 0xc000159f48)
$HOME/go/pkg/mod/github.com/spf13/[email protected]/command.go:950 +0x375
github.com/spf13/cobra.(*Command).Execute(...)
$HOME/go/pkg/mod/github.com/spf13/[email protected]/command.go:887
main.main()
$HOME/Sync/informal-systems/contracts/themis-contract/cmd/themis-contract/main.go:14 +0xc5
themis-contract new git://github.com:informalsystems/themis-contract/examples/service-agreement/contract.dhall#shon/v2-debug-error-on-new -v
[...]
6:55PM DBG git commit output:
[shon/v2-debug-error-on-new a47015a] Add new contract
2 files changed, 84 insertions(+)
create mode 100644 cmd/themis-contract/contract.dhall/contract.dhall
create mode 100644 cmd/themis-contract/contract.dhall/params.dhall
When I run neat-contract new
on the current contractor-agreement-template.tex
:
[sf@comp employment-contract]$ neat-contract new --template ../../compcomm/contract-templates/contractor-agreement/contractor-agreement-template.tex ./test-contract.tml
? Select from predefined counterparties
2020-03-08 14:09:03 error Parse error on line 1:
{{=<< >>=}}\documentcl
--^
Expecting 'ID', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'EQUALS'
This is generally desirable. E.g., I don't have the default Sacramento font installed, so I have to remember to add a --font
flag every time I sign. I'd like to set this once somewhere.
A lightweight approach that a lot of CLI tools I use adopt is to make make every flag option also something you can set via an envvar. E.g., I'd love to be able to just drop THEMIS_FONT=foo
into my bashrc.
A config file located in the .themis/contract
dir would also be OK.
(Notes from video sync with @thanethomson.)
For internal (and eventually external users) we'll want some packaging that can handle the system dependencies. We might start with a bash script (as discussed) but we could also consider using using system package managers (e.g.g, homebrew, apt).
We could also consider making a nix package, which should provide flexible cross-platform package management. I'd be willing to explore packing it via nix if we agreed this would be worth exploring.
In any case, we'll probably want to help users configure their node packages to install locally to a user, so as not to need root access. See https://github.com/glenpike/npm-g_nosudo for a script that does this.
The readme current instructs users to run npm i -g
to install the package globally. On my system, this resulted in a broken installation, since the globby
package was not installed but it is a transitive runtime dependency.
I suspect this is because it is only listed as a devDependencies
https://github.com/informalsystems/neat-contract/blob/master/package.json#L51 but doesn't appear in dependencies
.
With Thane's help, I was able to get a global install with npm i && npm i -g
.
Currently users have to:
It would provide a cleaner UI if we wrap (1) - (2) and (5) - (6) in some porcelain. We could download the repositories into the ~/.neat
directory and make the list of signed contracts available. Registering a repo could just be a matter of pasting the giturl.
As per discussion on #28
Tried to run the command to create a new contract and after inputing the template location, got an error message that the $EDITOR environment variable needs to be set. Probably a better UX would be to prompt the user to configure the environment variable before proceeding with the questions because in this case a contract.toml was actually created but without the parameters filled in.
$ themis-contract new
? Would you like to prepopulate the contract with variables from a template? Yes
? Where is the template located? (Git/HTTPS URL or file path) {URL TYPED HERE}
2020-05-20 14:17:03 info Created new contract: contract.toml
2020-05-20 14:17:03 error
Your $EDITOR environment variable is not set.
Set it to the command/path of your editor in ~/.zshenv or ~/.bashrc:
export EDITOR=atom
Currently, generating, compiling, and signing are three different steps. While this is great for low level plumbing, ultimately this should be possible by a single command.
This will be critical to demonstrate the value of the tool in more rapidly firing off contracts.
Following from the conversation on #25, we hopefully have room to discuss our approach to dealing with contracts and contract templates. I think a good starting point would be to break down conceptually and interrogate what's necessary to generate a final contract artifact, which I assume is a PDF document with zero or more signatures rendered into it. To render such a contract, we need:
I'll call these components the contract source elements for now.
I have some UX hypotheses that I'd like to lay out here which we could confirm/refute over the coming weeks where we could devise small experiments and test them out on users and/or ask them. These should help shape the approach we take to structuring our contracts and/or contract templates.
If there are other UX hypotheses anyone wants to add, please comment below and I'll add them to the list.
Generally, our contracting preparation goes something like this:
I think it could improve our process, and open up some avenues for for more structured gathering and representation of data to represent (at least some of) these distinct phases in the tooling. (E.g., perhaps we want to start tracking the "state" of a contract through some meta-data?)
Possible commands would be
themis-contract prepare foo
: (1) -> (3) -- Given a template id foo
, this would produce a partially configured contract, after collecting from the preparer additional information needed, including the destination repository and directory where the external party with interact with the contract. This could also post the partial configuration there, and notify the party via email.themis-contract fill foo
: (3) -> (4) -- Would prompt the external party to supply all the missing information, then present the filled contract for review. It could also prompt them to either accept and sign or make changes.themis-contract ammend foo
: (4) -- Could be useful for structuring the process of making changes.The existing sign
command would pick up from there.
Once counterparties are added to your profile, it should be possible to set them in the environment, like you can activate a python virtualenv.
Then you don't need to worry about specifying who you are in the contract and what your signatory is, it's already there in the environment and can be populated in the params file by default.
This will dramatically improve the UX by reducing the need to type out redundant information. Most people will have only one company/signatory to set and activate and all contracts will come from them. For others there may be multiple, but it should be easy to switch between them - easier than typing in who you are into the params file or as a flag in one of the commands.
Eg. themis-contract workas informal-systems ebuchman
... probably needs some work but something like that ... then all contracts will have informal-systems as a counterparty with ebuchman as a signatory
There is a potential workflow where someone may want to use DocuSign to facilitate signing instead of using the tool's built-in Keybase-based signing functionality. One could integrate with DocuSign's API.
NOTE: DocuSign API integration is a paid feature of DocuSign, but sandbox access is free for development purposes.
We need a docker image.
I haven't had the patience to fully install the dependencies. This is critical if people are actually going to use it.
The current default is now to register a keybase identity, though the readme suggests the opposite.
Would be good to outline both options in the readme.
Somewhat related to #2
I found the script a bit weird, and ended up copying and pasting what I needed.
For instance, it installs git
. I think it's safe to assume the user already has git.
It also seems to assume the user doesn't have the local repo. I think we can expect folks to clone the repo and build from within the repo. This should simplify all the /tmp
stuff.
Folks likely already have some version of node, and maybe don't want to use brew for it.
I think it would be best to include instructions for installation directly in the readme, consisting of a very small set of commands necessary to install the binary, assuming the dependencies are already installed and we're inside the repo.
Oh, we should also mention that we expect $EDITOR
to be set.
Trying to follow the readme instructions for installing from source, but hit:
$ make install
cd pkg/themis-contract/ && statik -src=../../assets/
/bin/sh: statik: command not found
make: *** [Makefile:11: build] Error 127
``
I can't figure out how actually use this flag to sign with an image. When I try to sign a contract with, I am prompted for the counterparty, then the identity, signatory, then prompted for an identity but given no options to select. And pressing return
results in a uncaught exception:
[sf@comp example]$ themis-contract sign --useimages
? On behalf of which counterparty will you be signing the contract? Angela Davis
? As which signatory will you be signing on behalf of the counterparty? Angela Davis
? Which identity do you want to use to sign?
(node:344007) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'value' of undefined
at ListPrompt.getCurrentValue (/home/sf/Sync/informal-systems/contracts/themis-contract/node_modules/inquirer/lib/prompts/list.js:121:53)
at MapSubscriber._next (/home/sf/Sync/informal-systems/contracts/themis-contract/node_modules/rxjs/src/internal/operators/map.ts:84:29)
at MapSubscriber.Subscriber.next (/home/sf/Sync/informal-systems/contracts/themis-contract/node_modules/rxjs/src/internal/Subscriber.ts:99:12)
at TakeSubscriber._next (/home/sf/Sync/informal-systems/contracts/themis-contract/node_modules/rxjs/src/internal/operators/take.ts:92:24)
at TakeSubscriber.Subscriber.next (/home/sf/Sync/informal-systems/contracts/themis-contract/node_modules/rxjs/src/internal/Subscriber.ts:99:12)
at Interface.handler (/home/sf/Sync/informal-systems/contracts/themis-contract/node_modules/rxjs/src/internal/observable/fromEvent.ts:201:20)
at Interface.emit (events.js:327:22)
at Interface._onLine (readline.js:337:10)
at Interface._line (readline.js:666:8)
at Interface._ttyWrite (readline.js:1006:14)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:344007) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:344007) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
When new
prompts for a path to a template from which param variables will be extracted, it doesn't recognize paths given relative to home with ~
.
E.g.,
? Where is the template located? (Git/HTTPS URL or file path) ~/Sync/informal-systems/porter/employment-contract/manual-port/template/employment-agreeement-template.tex
? Select from predefined counterparties
2020-03-08 14:00:01 error ENOENT: no such file or directory, open '/home/sf/Sync/informal-systems/porter/employment-contract/~/Sync/informal-systems/porter/employment-contract/manual-port/template/employment-agreeement-template.tex'
The new
command extracts parameters from out of a contract template and makes a config file for these params.
The immediate shortcomings in the current parameter extraction are:
new
sets the parameter with an empty string in the config instead of the proper object.This might not really be doable in a satisfactorily way for mustache, due to issues like janl/mustache.js#538 (comment)
This was discussed during our walk through of the tool last week.
We currently have a lot of high level commands.
I suspect we can get a better UX with some more hierarchical structure. eg. themis-contract id add
and themis-contract id list
instead of save-identity
and list-identity
. See the gaiacli
tool for instance.
Also there's probably a better way to structure the id/counterparty/signatory distinctions, but I don't exactly know yet.
Contract templates to be revised, whether because of negotiation or because circumstances and requirements change. With what we currently have in place, revision can effect two documents:
The process for the first is easy enough: parties can make changes to the repository holding the parameters, to change the specific terms of an agreement.
But what's the process for revising templates? If changes are just internal, and due to changing business needs, they can be unilaterally changed and incorporated into the template. But for negotiation between parties, it's not so clear. Two options that occur to me:
Currently, if there's a mistake or update needed for some added signatory, users have to edit the hidden state files. We should have a way of editing and updating these.
Discussed in our walkthrough last week.
Currently, themis-contract
can derive a partial (and generally malformed) configuration by extracting the parameters from a template. This saves time, but as we've seen through internal use, we really want to start working from a parameter configuration which has much more context available. The context should include information like
Eventually, we might be able to automate this process to some extent by inspecting the context of the passages in which the parameters appear, but this pushes us towards NLP, and such a clever solution isn't necessary and won't add much value to the current process. This is largely due to the fact that porting a contract to a parameterized template invariable involves creating an example configuration to test the port, and because the only interesting problem in such porting is modeling the domain (of which the configuration is just a representation).
To meet the immediate need and improve UI, we can make the new
subcommand (and the proposed prepare
#46) pull both a contract template and a default configuration (if available) from the source repo.
Is there someway the parameter file can be generated with comments for each parameter? Ideally parameters are named well enough so this isn't necessary and everything is obvious. We need to avoid a UX where you have to go back through the template to understand what the parameter is. But in some cases params may be more complex or ambiguous, so maybe some annotation in the contract can be copied into the params file as a comment?
When saving an identity, themis-contract
should not prompt for the ID of the key associated with the identity if there's only a single PGP key associated with the e-mail address of that identity:
Please enter the 70-char hex key ID for the Keybase key you would like to use:
This prompt should only ever appear if you have multiple PGP keys associated with a single identity. Right now it appears even when you only have a single key for the identity.
The easiest way to obtain this key in the meantime is to run:
> keybase pgp list
Keybase Key ID: <1234abcd...>
...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.