Giter VIP home page Giter VIP logo

themis-contract's Introduction

NOTE: This repository is no longer supported or updated by Informal Systems. If you wish to continue to develop this code yourself, we recommend you fork it.

Themis Contract ๐Ÿ–‹

Overview

Themis Contract is a command line-based tool to help with legal contracting. It currently aims to:

  1. Make contracting modular (in a decentralized way).
  2. Make contracting more programmatic (and eventually executable) than is traditionally the case.
  3. Make managing contracts more like managing software (so we can leverage the value that software development processes offer, like version control, continuous integration, etc.).

Disclaimer

Themis Contract is considered alpha quality at present. No semantic versioning will be used just yet. Breaking changes can be released at any time. For the original NodeJS-based prototype of Themis Contract, please see the prototype/v1 branch.

๐Ÿ™‹๐Ÿพโ€โ™€๏ธ Get Involved

  • Say hi in one of our chat rooms ๐Ÿ’ฌ
    • Register on Zulip, our chat platform
    • #introductions is a great place to start
    • #disco-tools is for discussing tooling for distributed co-op organizations (including themis-contract)

Installation

Packaged

MacOS

Use homebrew to Install from the informal.systems tap:

brew install informalsystems/pkgs/themis-contract

Manually

Requirements

In order to install Themis Contract locally, you will need:

Pre-built binaries

Once you have the requirements installed locally, you can simply download the latest release binary for your platform (right now we only build for Linux and MacOS) and put it somewhere in your path (e.g. /usr/local/bin/themis-contract).

From Source

To install from source:

git clone https://github.com/informalsystems/themis-contract.git
cd themis-contract
# once-off
make deps
# Optionally setting THEMIS_INSTALL_DIR to your desired location
# (default is to /usr/local/bin/)
THEMIS_INSTALL_DIR=~/.local/bin make install

Usage

See the following tutorials for details as to how to set up and use Themis Contract to get the most out of it:

More tutorials will be coming soon!

Uninstalling

Since Themis Contract is just a single standalone binary, uninstalling just involves deleting that binary:

rm /usr/local/bin/themis-contract

# Optional: to delete all Themis Contract-related data
rm -rf ~/.themis/contract

Contributing

See CONTRIBUTING.md.

License

Copyright 2020 Informal Systems Inc.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

themis-contract's People

Contributors

andynog avatar patcon avatar shonfeder avatar thanethomson avatar zramsay avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

themis-contract's Issues

Add commands to streamline review and execution of a contract

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

  1. downloading the contract at the url (assuming #6)
  2. registering it in the known contracts (also assuming #6)
  3. opening the contract for review (prompt for which contract, and prompt for last registered)

and execute would take care of

  1. checking whether an id has been added
  2. if not, prompt user to add appropriate ID
  3. signing the contract with ID
  4. compile the contract
  5. commit and push the changes (assuming #6)

Do we really need those fonts?

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?

Clarify and enhance data model of counterparties and signatories

At present, our data model is as follows:

arch--2020-05-22

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:

  1. Always treating a counterparty as a collective can be rather tedious and can result in redundant information needing to be added for both. This turns out to be quite a common occurrence, since a large number of contracts take place between a company (collective) and an individual.
  2. Our current notion of "identities" is confusing with signatories. A better concept here might be to have "profiles" for users of Themis Contract.

From these two suggestions, our model can be altered to resemble the following:

prototypev2-arch--2020-05-25

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.

Example for `themis-contract new` fails due to hardcoded local path

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.

Porcelain to generate, compile, sign

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.

Fetching templates

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

Set user's ID during `init`

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.

Automatic key selection not working

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...>
...

Contracts should include a local copy of their template

This is motivated by two intersecting dynamics:

  1. The person internal to an organization should have access to all contract templates and their entire history, but external parties signing a contract should not. So we cannot rely on all parties being able pull the template from the source repo.
  2. We will almost certainly need to support ad-hoc negotiations and changes (see #23) and such changes need insight into the template, but shouldn't be shared with all parties (even internal parties).

Towards implementation: The prepare subcommand proposed in #46 could be used to prepare a directory that includes

  • a copy of the template, along with a url+git ref to its source in space-time and a hash verify it's original contents
  • a partially filled config, ready for the other party to complete

Break contract "preparation" into phases reflecting the usual workflow

Generally, our contracting preparation goes something like this:

  1. There is a template lawyers have prepared for the purpose
  2. On the basis of the template, someone from within the organization prepares a draft with some basic known information about the party and context (e.g., the parties name, their job title and description).
  3. The other party supplies additional information (e.g., their address, list of prior inventions).
  4. The other party reviews the contract, requesting any changes they see feet (negotiation / correction).
  5. The other party executes.
  6. Someone from within the org-executes.

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.

`new` subcommand can fail with a type error `string "" is not a function`

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!

Document how ot use --useimages flag for signing

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.

Eliminate keybase dependency

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:

  • Users not knowing how to obtain their 70 char keys
  • Users not having keybase accounts or not having access to them at remote locations
  • Difficulty with containerization

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.

Expand `~` in path during contract creation with `new`

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'

Work out best-practices/tooling for negotiating and drafting

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:

  1. The paramters file
  2. The template itself

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:

  1. Negotiation takes place on a fork, allowing private negotiation over the content to be effected through commits, conversation, and PRs. The parties responsible for drafting the template could then pull some or all of these changes into upstream fork at their discretion.
  2. Negotiation results in new parameterization of the template. In some cases, this is probably useful and advisable, but in other cases it should probably be avoided, unless the parties wants to invite negotiation over the terms in question.

Translation to/from Microsoft Word

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.

Add procelain to manage cloning, and committing to repos

Currently users have to:

  1. clone a contract repo
  2. cd into the repo
  3. compile and sign
  4. stage changes
  5. commit changes
  6. push back to repo

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.

Docker Image

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.

new command puts artifacts insdie directory called contract.dhall

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

Param generation using `new` errors out on moustache delimieter setting

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'

go get github.com/informalsystems/themis-contract fails

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.

Package installation

(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.

Counterparty environment

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

Decide on contract source elements approach for next iteration of prototype

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:

  1. The text of the contract itself, structured in a way that formatting can be applied to it. For this, given that we want the contract to be configurable, we need:
    1. A contract template with placeholders for the configurable parts.
    2. The values that need to be injected into, or override, the configurable parts. These values could be specified directly or indirectly (i.e. they may need to be computed).
  2. Signatures for zero or more signatories (only when all signatories have signed do we consider a contract to be "complete").
  3. Formatting configuration to control how the contract is rendered (fonts, font sizes, letterhead, footers, etc.).
  4. (Optional) Images that make up part of the contract (it's not clear whether this is important right now though).

I'll call these components the contract source elements for now.


UX Hypotheses

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.

  • 1. Users want to be able to compose contracts by taking the "best"/most relevant parts of other existing (tried and tested) contracts and stringing them together as needed. (This seems self-evident due to our desire for contract templates in the first place.)
  • 2. Users are more comfortable composing contracts in a templating language (e.g. Markdown/Jinja2) than in a programming language (e.g. Dhall). See 3 below
  • 3. Users are more comfortable composing contracts in a templating language (e.g. Markdown/Jinja2) than in a configuration language (e.g. TOML). (The latter being our current approach with Themis Contract.) It appears as though we're fine with using a configuration language as an entrypoint into the contract.
  • 4. Users don't mind having formatting configuration be defined somewhere other than within/alongside the contract (i.e. they don't mind having it as part of their profile on their local machine).
  • 5. Users want to be able to customize contract formatting on a per-contract basis.
  • 6. Users care whether contract source elements are organized within a single file as opposed to multiple files (this is my skeuomorphic hypothesis). The multi-file approach means contract source elements must be organized into folders if they are to be cleanly separated from one another, whereas the single-file approach means that multiple contracts can be stored in a single folder alongside each other. Users are fine so far with the multi-file approach.
  • 7. Users would prefer to edit a full copy of the parameterized contract template (e.g. in Markdown/LaTeX) than use a templating, configuration or programming language to define their contracts. (Diffs here could easily be obtained by (1) including a reference to the original template in the contract, and (2) just doing a simple diff to see what changed from the template to the current contract.) This is effectively taken care of by including a local copy of the original template as per #47.

If there are other UX hypotheses anyone wants to add, please comment below and I'll add them to the list.

Add command to update template hash

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.

Add ability to select font for signing

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.

Add support for a default parameter config

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

  • how to supply parameters (what kinds of types and inputs are valid)
  • what they default to (in case of optional parameters)
  • and what they mean (when self-documenting names are not feasible)

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.

Add DocuSign integration

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.

Clean up install script

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.

Add ability to remove/change signatories

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.

Add flag to watch sorce file and recompile on changes

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
}

If environment variable is needed before running a command, show error before proceeding with questions

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

CLI Command Organization

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.

Add design for package management system

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:

  1. The file system/folder structure for what constitutes a template.
  2. The file system/folder structure for what constitutes a contract.

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.

Handling of file paths with `new` subcommand is confused

[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.

Support using persistent user configuration for most flag functionality

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.

Attempting to compile a contract results in seg fault

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

Comments in parameter file

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?

The `globby` dependency is not being installed using the documented installation command

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.

Parameter extraction from tempates is error prone

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:

  • Objects are sometimes not identified correctly, so new sets the parameter with an empty string in the config instead of the proper object.
  • There is no way to include any context or documentation to help inform users what the parameters are for.

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.

Related to #48 and #42

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.